/dist/
/unicode-downloads
/target
+/src/bootstrap/target
/src/tools/x/target
# Created by default with `src/ci/docker/run.sh`
/obj/
"typenum",
]
-[[package]]
-name = "block-buffer"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
-dependencies = [
- "block-padding",
- "byte-tools",
- "byteorder",
- "generic-array 0.12.4",
-]
-
[[package]]
name = "block-buffer"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
dependencies = [
- "generic-array 0.14.4",
-]
-
-[[package]]
-name = "block-padding"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
-dependencies = [
- "byte-tools",
+ "generic-array",
]
[[package]]
"toml",
]
-[[package]]
-name = "byte-tools"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
-
[[package]]
name = "bytecount"
version = "0.6.2"
"packed_simd_2",
]
-[[package]]
-name = "byteorder"
-version = "1.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
-
[[package]]
name = "bytes"
version = "1.0.1"
[[package]]
name = "clap"
-version = "3.2.5"
+version = "3.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d53da17d37dba964b9b3ecb5c5a1f193a2762c700e6829201e645b9381c99dc7"
+checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
dependencies = [
"atty",
"bitflags",
[[package]]
name = "clap_derive"
-version = "3.2.5"
+version = "3.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c11d40217d16aee8508cc8e5fde8b4ff24639758608e5374e731b53f85749fb9"
+checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
dependencies = [
"heck",
"proc-macro-error",
[[package]]
name = "combine"
-version = "4.6.3"
+version = "4.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062"
+checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
dependencies = [
"bytes",
"memchr",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06"
dependencies = [
- "generic-array 0.14.4",
+ "generic-array",
]
[[package]]
"quote",
]
-[[package]]
-name = "ctor"
-version = "0.1.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c"
-dependencies = [
- "quote",
- "syn",
-]
-
[[package]]
name = "curl"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
-[[package]]
-name = "digest"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
-dependencies = [
- "generic-array 0.12.4",
-]
-
[[package]]
name = "digest"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837"
dependencies = [
- "block-buffer 0.10.2",
+ "block-buffer",
"crypto-common",
]
name = "error_index_generator"
version = "0.0.0"
dependencies = [
- "rustdoc",
+ "mdbook",
]
[[package]]
"once_cell",
]
-[[package]]
-name = "fake-simd"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
-
[[package]]
name = "fallible-iterator"
version = "0.2.0"
"termcolor",
]
-[[package]]
-name = "generic-array"
-version = "0.12.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
-dependencies = [
- "typenum",
-]
-
[[package]]
name = "generic-array"
version = "0.14.4"
[[package]]
name = "handlebars"
-version = "4.1.0"
+version = "4.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72a0ffab8c36d0436114310c7e10b59b3307e650ddfabf6d006028e29a70c6e6"
+checksum = "360d9740069b2f6cbb63ce2dbaa71a20d3185350cbb990d7bebeb9318415eb17"
dependencies = [
"log",
"pest",
"pest_derive",
- "quick-error 2.0.0",
"serde",
"serde_json",
+ "thiserror",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
- "quick-error 1.2.3",
+ "quick-error",
]
[[package]]
[[package]]
name = "im-rc"
-version = "15.0.0"
+version = "15.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f"
+checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe"
dependencies = [
"bitmaps",
- "rand_core 0.5.1",
- "rand_xoshiro 0.4.0",
+ "rand_core 0.6.2",
+ "rand_xoshiro",
"sized-chunks",
"typenum",
"version_check",
"rustc-std-workspace-core",
]
+[[package]]
+name = "libffi"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e454b3efb16fba3b17810ae5e41df02b649e564ab3c5a34b3b93ed07ad287e6"
+dependencies = [
+ "libc",
+ "libffi-sys",
+]
+
+[[package]]
+name = "libffi-sys"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab4106b7f09d7b87d021334d5618fac1dfcfb824d4c5fe111ff0074dfd242e15"
+dependencies = [
+ "cc",
+]
+
[[package]]
name = "libgit2-sys"
version = "0.14.0+1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6a38fc55c8bbc10058782919516f88826e70320db6d206aebc49611d24216ae"
dependencies = [
- "digest 0.10.2",
+ "digest",
]
[[package]]
"getrandom 0.2.0",
"lazy_static",
"libc",
+ "libffi",
+ "libloading",
"log",
"measureme",
"rand 0.8.5",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
-[[package]]
-name = "opaque-debug"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
-
[[package]]
name = "opener"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
-[[package]]
-name = "output_vt100"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
-dependencies = [
- "winapi",
-]
-
[[package]]
name = "owo-colors"
version = "3.4.0"
[[package]]
name = "pest"
-version = "2.1.3"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
+checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4"
dependencies = [
+ "thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
-version = "2.1.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
+checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91"
dependencies = [
"pest",
"pest_generator",
[[package]]
name = "pest_generator"
-version = "2.1.3"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
+checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad"
dependencies = [
"pest",
"pest_meta",
[[package]]
name = "pest_meta"
-version = "2.1.3"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
+checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04"
dependencies = [
- "maplit",
+ "once_cell",
"pest",
- "sha-1 0.8.2",
+ "sha-1",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
-[[package]]
-name = "pretty_assertions"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563"
-dependencies = [
- "ansi_term",
- "ctor",
- "diff",
- "output_vt100",
-]
-
[[package]]
name = "pretty_env_logger"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
-[[package]]
-name = "quick-error"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ac73b1112776fc109b2e61909bc46c7e1bf0d7f690ffb1676553acce16d5cda"
-
[[package]]
name = "quine-mc_cluskey"
version = "0.2.4"
"rand_core 0.5.1",
]
-[[package]]
-name = "rand_xoshiro"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004"
-dependencies = [
- "rand_core 0.5.1",
-]
-
[[package]]
name = "rand_xoshiro"
version = "0.6.0"
"bstr",
"clap",
"libz-sys",
- "memchr",
"regex",
"serde_json",
"syn",
"rustc_macros",
"rustc_serialize",
"rustc_span",
+ "rustc_target",
"serde",
"serde_json",
"termcolor",
"gsgdt",
"polonius-engine",
"rand 0.8.5",
- "rand_xoshiro 0.6.0",
+ "rand_xoshiro",
"rustc-rayon",
"rustc-rayon-core",
"rustc_apfloat",
"rustc_macros",
"rustc_serialize",
"scoped-tls",
- "sha-1 0.10.0",
+ "sha-1",
"sha2",
"tracing",
"unicode-width",
dependencies = [
"itertools",
"rustc_data_structures",
+ "rustc_hir",
"rustc_infer",
"rustc_macros",
"rustc_middle",
"serde",
]
-[[package]]
-name = "sha-1"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
-dependencies = [
- "block-buffer 0.7.3",
- "digest 0.8.1",
- "fake-simd",
- "opaque-debug",
-]
-
[[package]]
name = "sha-1"
version = "0.10.0"
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
- "digest 0.10.2",
+ "digest",
]
[[package]]
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
- "digest 0.10.2",
+ "digest",
]
[[package]]
[[package]]
name = "thiserror"
-version = "1.0.30"
+version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
+checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.30"
+version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
+checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "ui_test"
-version = "0.1.0"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d1f546a5883ae78da735bba529ec1116661e2f73582f23920d994dc97da3a22"
dependencies = [
"cargo_metadata 0.15.0",
"color-eyre",
"colored",
"crossbeam",
+ "diff",
"lazy_static",
- "pretty_assertions",
"regex",
"rustc_version",
"serde",
// In a type expression `_` is an inference variable.
PatKind::Wild => TyKind::Infer,
// An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`.
- PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => {
+ PatKind::Ident(BindingAnnotation::NONE, ident, None) => {
TyKind::Path(None, Path::from_ident(*ident))
}
PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
pub is_placeholder: bool,
}
-#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
-pub enum BindingMode {
- ByRef(Mutability),
- ByValue(Mutability),
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
+pub enum ByRef {
+ Yes,
+ No,
+}
+
+impl From<bool> for ByRef {
+ fn from(b: bool) -> ByRef {
+ match b {
+ false => ByRef::No,
+ true => ByRef::Yes,
+ }
+ }
+}
+
+/// Explicit binding annotations given in the HIR for a binding. Note
+/// that this is not the final binding *mode* that we infer after type
+/// inference.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
+pub struct BindingAnnotation(pub ByRef, pub Mutability);
+
+impl BindingAnnotation {
+ pub const NONE: Self = Self(ByRef::No, Mutability::Not);
+ pub const REF: Self = Self(ByRef::Yes, Mutability::Not);
+ pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
+ pub const REF_MUT: Self = Self(ByRef::Yes, Mutability::Mut);
+
+ pub fn prefix_str(self) -> &'static str {
+ match self {
+ Self::NONE => "",
+ Self::REF => "ref ",
+ Self::MUT => "mut ",
+ Self::REF_MUT => "ref mut ",
+ }
+ }
}
#[derive(Clone, Encodable, Decodable, Debug)]
/// or a unit struct/variant pattern, or a const pattern (in the last two cases the third
/// field must be `None`). Disambiguation cannot be done with parser alone, so it happens
/// during name resolution.
- Ident(BindingMode, Ident, Option<P<Pat>>),
+ Ident(BindingAnnotation, Ident, Option<P<Pat>>),
/// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
/// The `bool` is `true` in the presence of a `..`.
impl Param {
/// Attempts to cast parameter to `ExplicitSelf`.
pub fn to_self(&self) -> Option<ExplicitSelf> {
- if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.kind {
+ if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), ident, _) = self.pat.kind {
if ident.name == kw::SelfLower {
return match self.ty.kind {
TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param {
let span = eself.span.to(eself_ident.span);
let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span, tokens: None });
- let param = |mutbl, ty| Param {
+ let (mutbl, ty) = match eself.node {
+ SelfKind::Explicit(ty, mutbl) => (mutbl, ty),
+ SelfKind::Value(mutbl) => (mutbl, infer_ty),
+ SelfKind::Region(lt, mutbl) => (
+ Mutability::Not,
+ P(Ty {
+ id: DUMMY_NODE_ID,
+ kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }),
+ span,
+ tokens: None,
+ }),
+ ),
+ };
+ Param {
attrs,
pat: P(Pat {
id: DUMMY_NODE_ID,
- kind: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None),
+ kind: PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), eself_ident, None),
span,
tokens: None,
}),
ty,
id: DUMMY_NODE_ID,
is_placeholder: false,
- };
- match eself.node {
- SelfKind::Explicit(ty, mutbl) => param(mutbl, ty),
- SelfKind::Value(mutbl) => param(mutbl, infer_ty),
- SelfKind::Region(lt, mutbl) => param(
- Mutability::Not,
- P(Ty {
- id: DUMMY_NODE_ID,
- kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }),
- span,
- tokens: None,
- }),
- ),
}
}
}
static_assert_size!(Fn, 192);
static_assert_size!(ForeignItem, 96);
static_assert_size!(ForeignItemKind, 24);
+ static_assert_size!(GenericArg, 24);
static_assert_size!(GenericBound, 88);
static_assert_size!(Generics, 72);
static_assert_size!(Impl, 200);
static_assert_size!(ItemKind, 112);
static_assert_size!(Lit, 48);
static_assert_size!(LitKind, 24);
+ static_assert_size!(Local, 72);
+ static_assert_size!(Param, 40);
static_assert_size!(Pat, 120);
static_assert_size!(PatKind, 96);
static_assert_size!(Path, 40);
#[macro_use]
extern crate rustc_macros;
+#[macro_use]
+extern crate tracing;
+
pub mod util {
pub mod classify;
pub mod comments;
use rustc_span::Span;
use std::ascii;
-use tracing::debug;
pub enum LitError {
NotLiteral,
let op = match *op {
InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
reg: lower_reg(reg),
- expr: self.lower_expr_mut(expr),
+ expr: self.lower_expr(expr),
},
InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
reg: lower_reg(reg),
late,
- expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
+ expr: expr.as_ref().map(|expr| self.lower_expr(expr)),
},
InlineAsmOperand::InOut { reg, late, ref expr } => {
hir::InlineAsmOperand::InOut {
reg: lower_reg(reg),
late,
- expr: self.lower_expr_mut(expr),
+ expr: self.lower_expr(expr),
}
}
InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
hir::InlineAsmOperand::SplitInOut {
reg: lower_reg(reg),
late,
- in_expr: self.lower_expr_mut(in_expr),
- out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
+ in_expr: self.lower_expr(in_expr),
+ out_expr: out_expr.as_ref().map(|expr| self.lower_expr(expr)),
}
}
InlineAsmOperand::Const { ref anon_const } => {
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
));
- let args = self.arena.alloc_from_iter(
- [&*receiver].into_iter().chain(args.iter()).map(|x| self.lower_expr_mut(x)),
- );
- hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span))
+ let receiver = self.lower_expr(receiver);
+ let args =
+ self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x)));
+ hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(span))
}
ExprKind::Binary(binop, ref lhs, ref rhs) => {
let binop = self.lower_binop(binop);
let (pat, task_context_hid) = self.pat_ident_binding_mode(
span,
Ident::with_dummy_span(sym::_task_context),
- hir::BindingAnnotation::Mutable,
+ hir::BindingAnnotation::MUT,
);
let param = hir::Param {
hir_id: self.next_id(),
// this name to identify what is being awaited by a suspended async functions.
let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
let (awaitee_pat, awaitee_pat_hid) =
- self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::Mutable);
+ self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::MUT);
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
// `mut iter`
let iter = Ident::with_dummy_span(sym::iter);
let (iter_pat, iter_pat_nid) =
- self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::Mutable);
+ self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::MUT);
// `match Iterator::next(&mut iter) { ... }`
let match_expr = {
binding: hir::HirId,
attrs: AttrVec,
) -> hir::Expr<'hir> {
+ let hir_id = self.next_id();
+ let res = Res::Local(binding);
let expr_path = hir::ExprKind::Path(hir::QPath::Resolved(
None,
self.arena.alloc(hir::Path {
span: self.lower_span(span),
- res: Res::Local(binding),
- segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
+ res,
+ segments: arena_vec![self; hir::PathSegment::new(ident, hir_id, res)],
}),
));
use rustc_span::source_map::SourceMap;
use rustc_span::{Span, DUMMY_SP};
-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
definitions: &'a definitions::Definitions,
}
-#[tracing::instrument(level = "debug", skip(sess, definitions, bodies))]
+#[instrument(level = "debug", skip(sess, definitions, bodies))]
pub(super) fn index_hir<'hir>(
sess: &Session,
definitions: &definitions::Definitions,
}
impl<'a, 'hir> NodeCollector<'a, 'hir> {
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
debug_assert_eq!(self.owner, hir_id.owner);
debug_assert_ne!(hir_id.local_id.as_u32(), 0);
});
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn visit_item(&mut self, i: &'hir Item<'hir>) {
debug_assert_eq!(i.def_id, self.owner);
self.with_parent(i.hir_id(), |this| {
});
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
debug_assert_eq!(fi.def_id, self.owner);
self.with_parent(fi.hir_id(), |this| {
})
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
debug_assert_eq!(ti.def_id, self.owner);
self.with_parent(ti.hir_id(), |this| {
});
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
debug_assert_eq!(ii.def_id, self.owner);
self.with_parent(ii.hir_id(), |this| {
}
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) {
- if let Some(hir_id) = path_segment.hir_id {
- self.insert(path_span, hir_id, Node::PathSegment(path_segment));
- }
+ self.insert(path_span, path_segment.hir_id, Node::PathSegment(path_segment));
intravisit::walk_path_segment(self, path_span, path_segment);
}
allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
allow_gen_future: Some([sym::gen_future][..].into()),
allow_into_future: Some([sym::into_future][..].into()),
+ generics_def_id_map: Default::default(),
};
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
self.with_lctx(CRATE_NODE_ID, |lctx| {
let module = lctx.lower_mod(&c.items, &c.spans);
lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
- hir::OwnerNode::Crate(lctx.arena.alloc(module))
+ hir::OwnerNode::Crate(module)
})
}
}
impl<'hir> LoweringContext<'_, 'hir> {
- pub(super) fn lower_mod(&mut self, items: &[P<Item>], spans: &ModSpans) -> hir::Mod<'hir> {
- hir::Mod {
+ pub(super) fn lower_mod(
+ &mut self,
+ items: &[P<Item>],
+ spans: &ModSpans,
+ ) -> &'hir hir::Mod<'hir> {
+ self.arena.alloc(hir::Mod {
spans: hir::ModSpans {
inner_span: self.lower_span(spans.inner_span),
inject_use_span: self.lower_span(spans.inject_use_span),
},
item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_ref(x))),
- }
+ })
}
pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
params: &'hir [hir::Param<'hir>],
value: hir::Expr<'hir>,
) -> hir::BodyId {
- let body = hir::Body { generator_kind: self.generator_kind, params, value };
+ let body = hir::Body {
+ generator_kind: self.generator_kind,
+ params,
+ value: self.arena.alloc(value),
+ };
let id = body.id();
debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
// Check if this is a binding pattern, if so, we can optimize and avoid adding a
// `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
let (ident, is_simple_parameter) = match parameter.pat.kind {
- hir::PatKind::Binding(
- hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
- _,
- ident,
- _,
- ) => (ident, true),
+ hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => {
+ (ident, true)
+ }
// For `ref mut` or wildcard arguments, we can't reuse the binding, but
// we can keep the same name for the parameter.
// This lets rustdoc render it correctly in documentation.
let (move_pat, move_id) = this.pat_ident_binding_mode(
desugared_span,
ident,
- hir::BindingAnnotation::Mutable,
+ hir::BindingAnnotation::MUT,
);
let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id);
let move_stmt = this.stmt_let_pat(
GenericParamKind::Const { .. } => None,
GenericParamKind::Type { .. } => {
let def_id = self.local_def_id(id).to_def_id();
+ let hir_id = self.next_id();
+ let res = Res::Def(DefKind::TyParam, def_id);
let ty_path = self.arena.alloc(hir::Path {
span: param_span,
- res: Res::Def(DefKind::TyParam, def_id),
- segments: self.arena.alloc_from_iter([hir::PathSegment::from_ident(ident)]),
+ res,
+ segments: self
+ .arena
+ .alloc_from_iter([hir::PathSegment::new(ident, hir_id, res)]),
});
let ty_id = self.next_id();
let bounded_ty =
allow_try_trait: Option<Lrc<[Symbol]>>,
allow_gen_future: Option<Lrc<[Symbol]>>,
allow_into_future: Option<Lrc<[Symbol]>>,
+
+ /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
+ /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
+ /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
+ /// field from the original parameter 'a to the new parameter 'a1.
+ generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
}
trait ResolverAstLoweringExt {
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind;
- /// Record the map from `from` local def id to `to` local def id, on `generics_def_id_map`
- /// field.
- fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId);
- /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
- /// `generics_def_id_map` field.
- fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId;
}
impl ResolverAstLoweringExt for ResolverAstLowering {
fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind {
self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang)
}
-
- /// Push a remapping into the top-most map.
- /// Panics if no map has been pushed.
- /// Remapping is used when creating lowering `-> impl Trait` return
- /// types to create the resulting opaque type.
- #[tracing::instrument(level = "debug", skip(self))]
- fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId) {
- self.generics_def_id_map.last_mut().expect("no map pushed").insert(from, to);
- }
-
- fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId {
- // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we
- // push new mappings so we need to try first the latest mappings, hence `iter().rev()`.
- //
- // Consider:
- //
- // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}`
- //
- // We would end with a generics_def_id_map like:
- //
- // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]`
- //
- // for the opaque type generated on `impl Sized + 'b`, We want the result to be:
- // impl_sized#'b, so iterating forward is the wrong thing to do.
- for map in self.generics_def_id_map.iter().rev() {
- if let Some(r) = map.get(&local_def_id) {
- debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`");
- local_def_id = *r;
- } else {
- debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map");
- }
- }
-
- local_def_id
- }
}
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
self.resolver
.node_id_to_def_id
.get(&node)
- .map(|local_def_id| self.resolver.get_remapped_def_id(*local_def_id))
+ .map(|local_def_id| self.get_remapped_def_id(*local_def_id))
}
fn local_def_id(&self, node: NodeId) -> LocalDefId {
self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
}
+ /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
+ /// `generics_def_id_map` field.
+ fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId {
+ // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we
+ // push new mappings so we need to try first the latest mappings, hence `iter().rev()`.
+ //
+ // Consider:
+ //
+ // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}`
+ //
+ // We would end with a generics_def_id_map like:
+ //
+ // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]`
+ //
+ // for the opaque type generated on `impl Sized + 'b`, We want the result to be:
+ // impl_sized#'b, so iterating forward is the wrong thing to do.
+ for map in self.generics_def_id_map.iter().rev() {
+ if let Some(r) = map.get(&local_def_id) {
+ debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`");
+ local_def_id = *r;
+ } else {
+ debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map");
+ }
+ }
+
+ local_def_id
+ }
+
/// Freshen the `LoweringContext` and ready it to lower a nested item.
/// The lowered item is registered into `self.children`.
///
remap: FxHashMap<LocalDefId, LocalDefId>,
f: impl FnOnce(&mut Self) -> R,
) -> R {
- self.resolver.generics_def_id_map.push(remap);
+ self.generics_def_id_map.push(remap);
let res = f(self);
- self.resolver.generics_def_id_map.pop();
+ self.generics_def_id_map.pop();
res
}
}
/// Converts a lifetime into a new generic parameter.
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn lifetime_res_to_generic_param(
&mut self,
ident: Ident,
/// name resolver owing to lifetime elision; this also populates the resolver's node-id->def-id
/// map, so that later calls to `opt_node_id_to_def_id` that refer to these extra lifetime
/// parameters will be successful.
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
#[inline]
fn lower_lifetime_binder(
&mut self,
}
_ => {}
}
- GenericArg::Type(self.lower_ty_direct(&ty, itctx))
+ GenericArg::Type(self.lower_ty(&ty, itctx))
}
ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg {
value: self.lower_anon_const(&ct),
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
}
TyKind::ImplicitSelf => {
+ let hir_id = self.lower_node_id(t.id);
let res = self.expect_full_res(t.id);
let res = self.lower_res(res);
hir::TyKind::Path(hir::QPath::Resolved(
None,
self.arena.alloc(hir::Path {
res,
- segments: arena_vec![self; hir::PathSegment::from_ident(
- Ident::with_dummy_span(kw::SelfUpper)
+ segments: arena_vec![self; hir::PathSegment::new(
+ Ident::with_dummy_span(kw::SelfUpper),
+ hir_id,
+ res
)],
span: self.lower_span(t.span),
}),
/// added explicitly in the HIR). But this includes all the lifetimes, and we only want to
/// capture the lifetimes that are referenced in the bounds. Therefore, we add *extra* lifetime parameters
/// for the lifetimes that get captured (`'x`, in our example above) and reference those.
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn lower_opaque_impl_trait(
&mut self,
span: Span,
// `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
// return type. This is used for `async fn` declarations. The `NodeId` is the ID of the
// return type `impl Trait` item.
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn lower_fn_decl(
&mut self,
decl: &FnDecl,
output,
c_variadic,
implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
- use BindingMode::{ByRef, ByValue};
let is_mutable_pat = matches!(
arg.pat.kind,
- PatKind::Ident(ByValue(Mutability::Mut) | ByRef(Mutability::Mut), ..)
+ PatKind::Ident(hir::BindingAnnotation(_, Mutability::Mut), ..)
);
match arg.ty.kind {
// `output`: unlowered output type (`T` in `-> T`)
// `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
// `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn lower_async_fn_ret_ty(
&mut self,
output: &FnRetTy,
self.new_named_lifetime(l.id, l.id, span, ident)
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn new_named_lifetime_with_res(
&mut self,
id: NodeId,
let name = match res {
LifetimeRes::Param { param, .. } => {
let p_name = ParamName::Plain(ident);
- let param = self.resolver.get_remapped_def_id(param);
+ let param = self.get_remapped_def_id(param);
hir::LifetimeName::Param(param, p_name)
}
hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn new_named_lifetime(
&mut self,
id: NodeId,
hir::TraitRef { path, hir_ref_id: self.lower_node_id(p.ref_id) }
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn lower_poly_trait_ref(
&mut self,
p: &PolyTraitRef,
hir::PredicateOrigin::ImplTrait,
);
+ let hir_id = self.next_id();
+ let res = Res::Def(DefKind::TyParam, def_id.to_def_id());
let ty = hir::TyKind::Path(hir::QPath::Resolved(
None,
self.arena.alloc(hir::Path {
span: self.lower_span(span),
- res: Res::Def(DefKind::TyParam, def_id.to_def_id()),
- segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
+ res,
+ segments:
+ arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
}),
));
}
fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, hir::HirId) {
- self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::Unannotated)
+ self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::NONE)
}
fn pat_ident_mut(&mut self, span: Span, ident: Ident) -> (hir::Pat<'hir>, hir::HirId) {
- self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::Unannotated)
+ self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::NONE)
}
fn pat_ident_binding_mode(
let node = loop {
match pattern.kind {
PatKind::Wild => break hir::PatKind::Wild,
- PatKind::Ident(ref binding_mode, ident, ref sub) => {
+ PatKind::Ident(binding_mode, ident, ref sub) => {
let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub);
}
let mut prev_rest_span = None;
// Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
- let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| {
+ let lower_rest_sub = |this: &mut Self, pat, ann, ident, sub| {
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
- let node = this.lower_pat_ident(pat, bm, ident, lower_sub);
+ let node = this.lower_pat_ident(pat, ann, ident, lower_sub);
this.pat_with_node_id_of(pat, node)
};
}
// Found a sub-slice pattern `$binding_mode $ident @ ..`.
// Record, lower it to `$binding_mode $ident @ _`, and stop here.
- PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
+ PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => {
prev_rest_span = Some(sub.span);
- slice = Some(self.arena.alloc(lower_rest_sub(self, pat, bm, ident, sub)));
+ slice = Some(self.arena.alloc(lower_rest_sub(self, pat, ann, ident, sub)));
break;
}
// It was not a subslice pattern so lower it normally.
// There was a previous subslice pattern; make sure we don't allow more.
let rest_span = match pat.kind {
PatKind::Rest => Some(pat.span),
- PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
+ PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => {
// #69103: Lower into `binding @ _` as above to avoid ICEs.
- after.push(lower_rest_sub(self, pat, bm, ident, sub));
+ after.push(lower_rest_sub(self, pat, ann, ident, sub));
Some(sub.span)
}
_ => None,
fn lower_pat_ident(
&mut self,
p: &Pat,
- binding_mode: &BindingMode,
+ annotation: BindingAnnotation,
ident: Ident,
lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
) -> hir::PatKind<'hir> {
};
hir::PatKind::Binding(
- self.lower_binding_mode(binding_mode),
+ annotation,
self.lower_node_id(canonical_id),
self.lower_ident(ident),
lower_sub(self),
)
}
- Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
- None,
- self.arena.alloc(hir::Path {
- span: self.lower_span(ident.span),
- res: self.lower_res(res),
- segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
- }),
- )),
- }
- }
-
- fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
- match *b {
- BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated,
- BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref,
- BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable,
- BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut,
+ Some(res) => {
+ let hir_id = self.next_id();
+ let res = self.lower_res(res);
+ hir::PatKind::Path(hir::QPath::Resolved(
+ None,
+ self.arena.alloc(hir::Path {
+ span: self.lower_span(ident.span),
+ res,
+ segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
+ }),
+ ))
+ }
}
}
use rustc_span::{BytePos, Span, DUMMY_SP};
use smallvec::smallvec;
-use tracing::debug;
impl<'a, 'hir> LoweringContext<'a, 'hir> {
#[instrument(level = "trace", skip(self))]
}
let res = self.expect_full_res(segment.id);
- let id = self.lower_node_id(segment.id);
+ let hir_id = self.lower_node_id(segment.id);
debug!(
"lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
- segment.ident, segment.id, id,
+ segment.ident, segment.id, hir_id,
);
hir::PathSegment {
ident: self.lower_ident(segment.ident),
- hir_id: Some(id),
- res: Some(self.lower_res(res)),
+ hir_id,
+ res: self.lower_res(res),
infer_args,
args: if generic_args.is_empty() && generic_args.span.is_empty() {
None
}
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
};
- let args = smallvec![GenericArg::Type(self.ty_tup(*inputs_span, inputs))];
+ let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
let binding = self.output_ty_binding(output_ty.span, output_ty);
(
GenericArgsCtor {
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
for Param { pat, .. } in &decl.inputs {
match pat.kind {
- PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
- PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
+ PatKind::Ident(BindingAnnotation::NONE, _, None) | PatKind::Wild => {}
+ PatKind::Ident(BindingAnnotation::MUT, ident, None) => {
report_err(pat.span, Some(ident), true)
}
_ => report_err(pat.span, None, false),
use rustc_span::symbol::sym;
use rustc_span::Span;
-use tracing::debug;
-
macro_rules! gate_feature_fn {
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
let (visitor, has_feature, span, name, explain, help) =
#![feature(let_else)]
#![recursion_limit = "256"]
+#[macro_use]
+extern crate tracing;
+
pub mod ast_validation;
mod errors;
pub mod feature_gate;
use rustc_ast::util::classify;
use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
use rustc_ast::util::parser;
-use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use rustc_ast::{attr, Term};
+use rustc_ast::{self as ast, BlockCheckMode, Mutability, PatKind, RangeEnd, RangeSyntax};
+use rustc_ast::{attr, BindingAnnotation, ByRef, Term};
use rustc_ast::{GenericArg, MacArgs, MacArgsEq};
use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
is that it doesn't matter */
match pat.kind {
PatKind::Wild => self.word("_"),
- PatKind::Ident(binding_mode, ident, ref sub) => {
- match binding_mode {
- ast::BindingMode::ByRef(mutbl) => {
- self.word_nbsp("ref");
- self.print_mutability(mutbl, false);
- }
- ast::BindingMode::ByValue(ast::Mutability::Not) => {}
- ast::BindingMode::ByValue(ast::Mutability::Mut) => {
- self.word_nbsp("mut");
- }
+ PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, ref sub) => {
+ if by_ref == ByRef::Yes {
+ self.word_nbsp("ref");
+ }
+ if mutbl == Mutability::Mut {
+ self.word_nbsp("mut");
}
self.print_ident(ident);
if let Some(ref p) = *sub {
}
PatKind::Ref(ref inner, mutbl) => {
self.word("&");
- if mutbl == ast::Mutability::Mut {
+ if mutbl == Mutability::Mut {
self.word("mut ");
}
- if let PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Mut), ..) =
- inner.kind
- {
+ if let PatKind::Ident(ast::BindingAnnotation::MUT, ..) = inner.kind {
self.popen();
self.print_pat(inner);
self.pclose();
ast::ItemKind::GlobalAsm(ref asm) => {
self.head(visibility_qualified(&item.vis, "global_asm!"));
self.print_inline_asm(asm);
+ self.word(";");
+ self.end();
self.end();
}
ast::ItemKind::TyAlias(box ast::TyAlias {
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
+/// The version placeholder that recently stabilized features contain inside the
+/// `since` field of the `#[stable]` attribute.
+///
+/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
+pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
+
pub fn is_builtin_attr(attr: &Attribute) -> bool {
attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
}
}
}
+ if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
+ let version = option_env!("CFG_VERSION").unwrap_or("<current>");
+ let version = version.split(' ').next().unwrap();
+ since = Some(Symbol::intern(&version));
+ }
+
match (feature, since) {
(Some(feature), Some(since)) => {
let level = Stable { since, allowed_through_unstable_modules: false };
let ty = place.ty(self.body, self.infcx.tcx).ty;
// If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
- if is_loop_move & !in_pattern {
+ // Same for if we're in a loop, see #101119.
+ if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) {
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
err.span_suggestion_verbose(
if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
&& let hir::PatKind::Binding(
- hir::BindingAnnotation::Unannotated,
+ hir::BindingAnnotation::NONE,
_,
upvar_ident,
_,
Applicability::MachineApplicable,
);
self.suggested = true;
- } else if let hir::ExprKind::MethodCall(_path, args @ [_, ..], sp) = expr.kind
- && let hir::ExprKind::Index(val, index) = args[0].kind
+ } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
+ && let hir::ExprKind::Index(val, index) = receiver.kind
&& expr.span == self.assign_span
{
// val[index].path(args..);
".get_mut(".to_string(),
),
(
- index.span.shrink_to_hi().with_hi(args[0].span.hi()),
+ index.span.shrink_to_hi().with_hi(receiver.span.hi()),
").map(|val| val".to_string(),
),
(sp.shrink_to_hi(), ")".to_string()),
[
Expr {
kind:
- MethodCall(
- path_segment,
- _args,
- span,
- ),
+ MethodCall(path_segment, _, _, span),
hir_id,
..
},
_,
) = hir_map.body(fn_body_id).value.kind
{
- let opt_suggestions = path_segment
- .hir_id
- .map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner))
- .and_then(|typeck| typeck.type_dependent_def_id(*hir_id))
+ let opt_suggestions = self
+ .infcx
+ .tcx
+ .typeck(path_segment.hir_id.owner)
+ .type_dependent_def_id(*hir_id)
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
.map(|def_id| self.infcx.tcx.associated_items(def_id))
.map(|assoc_items| {
use rustc_middle::ty::RegionVid;
use smallvec::SmallVec;
use std::collections::BTreeMap;
-use tracing::debug;
use crate::MirBorrowckCtxt;
let mut closure_span = None::<rustc_span::Span>;
match expr.kind {
hir::ExprKind::MethodCall(.., args, _) => {
- // only the first closre parameter of the method. args[0] is MethodCall PathSegment
- for i in 1..args.len() {
- if let hir::ExprKind::Closure(..) = args[i].kind {
- closure_span = Some(args[i].span.shrink_to_lo());
+ for arg in args {
+ if let hir::ExprKind::Closure(hir::Closure {
+ capture_clause: hir::CaptureBy::Ref,
+ ..
+ }) = arg.kind
+ {
+ closure_span = Some(arg.span.shrink_to_lo());
break;
}
}
hir::ExprKind::Block(blk, _) => {
if let Some(ref expr) = blk.expr {
// only when the block is a closure
- if let hir::ExprKind::Closure(..) = expr.kind {
+ if let hir::ExprKind::Closure(hir::Closure {
+ capture_clause: hir::CaptureBy::Ref,
+ ..
+ }) = expr.kind
+ {
closure_span = Some(expr.span.shrink_to_lo());
}
}
if let Some(closure_span) = closure_span {
diag.span_suggestion_verbose(
closure_span,
- format!("consider adding 'move' keyword before the nested closure"),
+ "consider adding 'move' keyword before the nested closure",
"move ",
Applicability::MaybeIncorrect,
);
/// *user* has a name for. In that case, we'll be able to map
/// `fr` to a `Region<'tcx>`, and that region will be one of
/// named variants.
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
let error_region = self.to_error_region(fr)?;
/// | fn foo(x: &u32) { .. }
/// ------- fully elaborated type of `x` is `&'1 u32`
/// ```
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_arguments(
&self,
fr: RegionVid,
/// | let x = Some(&22);
/// - fully elaborated type of `x` is `Option<&'1 u32>`
/// ```
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
/// must be a closure since, in a free fn, such an argument would
/// have to either also appear in an argument (if using elision)
/// or be early bound (named, not in argument).
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
let tcx = self.infcx.tcx;
let hir = tcx.hir();
}
}
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_yield_ty(
&self,
fr: RegionVid,
/// include the CFG anyhow.
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
/// a result `'y`.
- #[instrument(skip(self), level = "debug")]
+ #[instrument(skip(self), level = "debug", ret)]
pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
debug!(r = %self.region_value_str(r));
lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
}
- debug!(?lub);
-
lub
}
}
// Evaluate whether `sup_region: sub_region`.
- #[instrument(skip(self), level = "debug")]
+ #[instrument(skip(self), level = "debug", ret)]
fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
debug!(
- "eval_outlives: sup_region's value = {:?} universal={:?}",
+ "sup_region's value = {:?} universal={:?}",
self.region_value_str(sup_region),
self.universal_regions.is_universal_region(sup_region),
);
debug!(
- "eval_outlives: sub_region's value = {:?} universal={:?}",
+ "sub_region's value = {:?} universal={:?}",
self.region_value_str(sub_region),
self.universal_regions.is_universal_region(sub_region),
);
// true if `'sup` outlives static.
if !self.universe_compatible(sub_region_scc, sup_region_scc) {
debug!(
- "eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \
+ "sub universe `{sub_region_scc:?}` is not nameable \
by super `{sup_region_scc:?}`, promoting to static",
);
});
if !universal_outlives {
- debug!(
- "eval_outlives: returning false because sub region contains a universal region not present in super"
- );
+ debug!("sub region contains a universal region not present in super");
return false;
}
if self.universal_regions.is_universal_region(sup_region) {
// Micro-opt: universal regions contain all points.
- debug!(
- "eval_outlives: returning true because super is universal and hence contains all points"
- );
+ debug!("super is universal and hence contains all points");
return true;
}
- let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc);
- debug!("returning {} because of comparison between points in sup/sub", result);
- result
+ debug!("comparison between points in sup/sub");
+
+ self.scc_values.contains_points(sup_region_scc, sub_region_scc)
}
/// Once regions have been propagated, this method is used to see
}
/// Finds some region R such that `fr1: R` and `R` is live at `elem`.
- #[instrument(skip(self), level = "trace")]
+ #[instrument(skip(self), level = "trace", ret)]
pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
trace!(scc = ?self.constraint_sccs.scc(fr1));
trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]);
/// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
/// which has no `external_name` in which case we use `'empty` as the
/// region to pass to `infer_opaque_definition_from_instantiation`.
- #[instrument(level = "debug", skip(self, infcx))]
+ #[instrument(level = "debug", skip(self, infcx), ret)]
pub(crate) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'_, 'tcx>,
mir_def_id: LocalDefId,
indices: &mut UniversalRegionIndices<'tcx>,
) {
- debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
- debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
+ debug!(?r);
if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR);
debug!(?region_vid);
use crate::deriving;
use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, EnumDef, Expr, Generics, PatKind};
+use rustc_ast::{
+ self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind,
+};
use rustc_ast::{GenericArg, GenericParamKind, VariantData};
use rustc_attr as attr;
use rustc_expand::base::{Annotatable, ExtCtxt};
let mut body = mk_body(cx, selflike_fields);
let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]);
- let use_ref_pat = is_packed && !always_copy;
+ let by_ref = ByRef::from(is_packed && !always_copy);
let patterns =
- trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, use_ref_pat);
+ trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, by_ref);
// Do the let-destructuring.
let mut stmts: Vec<_> = iter::zip(selflike_args, patterns)
let sp = variant.span.with_ctxt(trait_.span.ctxt());
let variant_path = cx.path(sp, vec![type_ident, variant.ident]);
- let use_ref_pat = false; // because enums can't be repr(packed)
+ let by_ref = ByRef::No; // because enums can't be repr(packed)
let mut subpats: Vec<_> = trait_.create_struct_patterns(
cx,
variant_path,
&variant.data,
&prefixes,
- use_ref_pat,
+ by_ref,
);
// `(VariantK, VariantK, ...)` or just `VariantK`.
struct_path: ast::Path,
struct_def: &'a VariantData,
prefixes: &[String],
- use_ref_pat: bool,
+ by_ref: ByRef,
) -> Vec<P<ast::Pat>> {
prefixes
.iter()
let pieces_iter =
struct_def.fields().iter().enumerate().map(|(i, struct_field)| {
let sp = struct_field.span.with_ctxt(self.span.ctxt());
- let binding_mode = if use_ref_pat {
- ast::BindingMode::ByRef(ast::Mutability::Not)
- } else {
- ast::BindingMode::ByValue(ast::Mutability::Not)
- };
let ident = self.mk_pattern_ident(prefix, i);
let path = ident.with_span_pos(sp);
(
sp,
struct_field.ident,
- cx.pat(path.span, PatKind::Ident(binding_mode, path, None)),
+ cx.pat(
+ path.span,
+ PatKind::Ident(
+ BindingAnnotation(by_ref, Mutability::Not),
+ path,
+ None,
+ ),
+ ),
)
});
extern crate proc_macro;
+#[macro_use]
+extern crate tracing;
+
use crate::deriving::*;
use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
// extern crate test
let test_extern = cx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None));
- tracing::debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
+ debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
if is_stmt {
vec![
use rustc_target::spec::PanicStrategy;
use smallvec::{smallvec, SmallVec};
use thin_vec::thin_vec;
-use tracing::debug;
use std::{iter, mem};
use rustc_hir::LangItem;
use rustc_middle::ty::subst::GenericArg;
use rustc_middle::ty::AssocKind;
-use rustc_session::config::EntryFnType;
+use rustc_session::config::{sigpipe, EntryFnType};
use rustc_span::symbol::Ident;
use crate::prelude::*;
is_jit: bool,
is_primary_cgu: bool,
) {
- let (main_def_id, is_main_fn) = match tcx.entry_fn(()) {
+ let (main_def_id, (is_main_fn, sigpipe)) = match tcx.entry_fn(()) {
Some((def_id, entry_ty)) => (
def_id,
match entry_ty {
- EntryFnType::Main => true,
- EntryFnType::Start => false,
+ EntryFnType::Main { sigpipe } => (true, sigpipe),
+ EntryFnType::Start => (false, sigpipe::DEFAULT),
},
),
None => return,
return;
}
- create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn);
+ create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn, sigpipe);
fn create_entry_fn(
tcx: TyCtxt<'_>,
rust_main_def_id: DefId,
ignore_lang_start_wrapper: bool,
is_main_fn: bool,
+ sigpipe: u8,
) {
let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
// Given that `main()` has no arguments,
bcx.switch_to_block(block);
let arg_argc = bcx.append_block_param(block, m.target_config().pointer_type());
let arg_argv = bcx.append_block_param(block, m.target_config().pointer_type());
+ let arg_sigpipe = bcx.ins().iconst(types::I8, sigpipe as i64);
let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);
let main_val = bcx.ins().func_addr(m.target_config().pointer_type(), main_func_ref);
let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
- let call_inst = bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv]);
+ let call_inst =
+ bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv, arg_sigpipe]);
bcx.inst_results(call_inst)[0]
} else {
// using user-defined start fn
use libc::{c_char, c_uint};
use smallvec::SmallVec;
-use tracing::debug;
impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
fn codegen_inline_asm(
) {
let span = cx
.tcx
- .get_attr(instance.def_id(), sym::target_feature)
+ .get_attrs(instance.def_id(), sym::target_feature)
+ .next()
.map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
let msg = format!(
"the target features {} must all be either enabled or disabled together",
let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
- tracing::trace!("invoking LLVMRustWriteImportLibrary");
- tracing::trace!(" dll_name {:#?}", dll_name_z);
- tracing::trace!(" output_path {}", output_path.display());
- tracing::trace!(
+ trace!("invoking LLVMRustWriteImportLibrary");
+ trace!(" dll_name {:#?}", dll_name_z);
+ trace!(" output_path {}", output_path.display());
+ trace!(
" import names: {}",
dll_imports
.iter()
use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{self, CrateType, Lto};
-use tracing::{debug, info};
use std::ffi::{CStr, CString};
use std::fs::File;
use rustc_span::symbol::sym;
use rustc_span::InnerSpan;
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo};
-use tracing::debug;
use libc::{c_char, c_int, c_uint, c_void, size_t};
use std::ffi::CString;
use std::iter;
use std::ops::Deref;
use std::ptr;
-use tracing::{debug, instrument};
// All Builders must have an llfn associated with them
#[must_use]
use crate::llvm;
use crate::value::Value;
use rustc_codegen_ssa::traits::*;
-use tracing::debug;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
use rustc_middle::ty::{self, Instance, TypeVisitable};
use libc::{c_char, c_uint};
use std::fmt::Write;
-use tracing::debug;
/*
* A note on nomenclature of linking: "extern", "foreign", and "upcall".
AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
};
use std::ops::Range;
-use tracing::debug;
pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value {
let alloc = alloc.inner();
use std::ffi::CString;
-use tracing::debug;
-
/// Generates and exports the Coverage Map.
///
/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions
use std::ffi::CString;
use std::iter;
-use tracing::debug;
pub mod mapgen;
use rustc_symbol_mangling::typeid_for_trait_ref;
use rustc_target::abi::{Align, Size};
use smallvec::smallvec;
-use tracing::debug;
use libc::{c_char, c_longlong, c_uint};
use std::borrow::Cow;
use std::iter;
use std::path::{Path, PathBuf};
use std::ptr;
-use tracing::instrument;
impl PartialEq for llvm::Metadata {
fn eq(&self, other: &Self) -> bool {
use std::cell::OnceCell;
use std::cell::RefCell;
use std::iter;
-use tracing::debug;
mod create_scope_map;
pub mod gdb;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
use rustc_middle::ty::{self, DefIdTree, Ty};
-use tracing::trace;
+use trace;
use crate::common::CodegenCx;
use crate::llvm;
use rustc_middle::ty::Ty;
use rustc_symbol_mangling::typeid::typeid_for_fnabi;
use smallvec::SmallVec;
-use tracing::debug;
/// Declare a function.
///
#[macro_use]
extern crate rustc_macros;
+#[macro_use]
+extern crate tracing;
use back::write::{create_informational_target_machine, create_target_machine};
use rustc_target::spec::{MergeFunctions, PanicStrategy};
use smallvec::{smallvec, SmallVec};
use std::ffi::{CStr, CString};
-use tracing::debug;
use std::mem;
use std::path::Path;
use rustc_middle::ty::{self, Instance, TypeVisitable};
use rustc_session::config::CrateType;
use rustc_target::spec::RelocModel;
-use tracing::debug;
impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
fn predefine_static(
use rustc_target::abi::{Int, Pointer, F32, F64};
use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants};
use smallvec::{smallvec, SmallVec};
-use tracing::debug;
use std::fmt::Write;
// only the linker flavor is known; use the default linker for the selected flavor
(None, Some(flavor)) => Some((
PathBuf::from(match flavor {
- LinkerFlavor::Em => {
- if cfg!(windows) {
- "emcc.bat"
- } else {
- "emcc"
- }
- }
LinkerFlavor::Gcc => {
if cfg!(any(target_os = "solaris", target_os = "illumos")) {
// On historical Solaris systems, "cc" may have
}
}
LinkerFlavor::Ld => "ld",
- LinkerFlavor::Msvc => "link.exe",
LinkerFlavor::Lld(_) => "lld",
- LinkerFlavor::PtxLinker => "rust-ptx-linker",
- LinkerFlavor::BpfLinker => "bpf-linker",
- LinkerFlavor::L4Bender => "l4-bender",
+ LinkerFlavor::Msvc => "link.exe",
+ LinkerFlavor::EmCc => {
+ if cfg!(windows) {
+ "emcc.bat"
+ } else {
+ "emcc"
+ }
+ }
+ LinkerFlavor::Bpf => "bpf-linker",
+ LinkerFlavor::Ptx => "rust-ptx-linker",
}),
flavor,
)),
});
let flavor = if stem == "emcc" {
- LinkerFlavor::Em
+ LinkerFlavor::EmCc
} else if stem == "gcc"
|| stem.ends_with("-gcc")
|| stem == "clang"
// linker and linker flavor specified via command line have precedence over what the target
// specification specifies
- if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) {
+ let linker_flavor = sess.opts.cg.linker_flavor.map(LinkerFlavor::from_cli);
+ if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) {
return ret;
}
});
}
- if flavor == LinkerFlavor::PtxLinker {
+ if flavor == LinkerFlavor::Ptx {
// Provide the linker with fallback to internal `target-cpu`.
cmd.arg("--fallback-arch");
cmd.arg(&codegen_results.crate_info.target_cpu);
- } else if flavor == LinkerFlavor::BpfLinker {
+ } else if flavor == LinkerFlavor::Bpf {
cmd.arg("--cpu");
cmd.arg(&codegen_results.crate_info.target_cpu);
cmd.arg("--cpu-features");
if let LinkerFlavor::Gcc = flavor {
match ld_impl {
LdImpl::Lld => {
- let tools_path = sess.get_tools_search_paths(false);
- let gcc_ld_dir = tools_path
- .into_iter()
- .map(|p| p.join("gcc-ld"))
- .find(|p| {
- p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists()
- })
- .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found"));
- cmd.arg({
- let mut arg = OsString::from("-B");
- arg.push(gcc_ld_dir);
- arg
- });
- cmd.arg(format!("-Wl,-rustc-lld-flavor={}", sess.target.lld_flavor.as_str()));
+ // Implement the "self-contained" part of -Zgcc-ld
+ // by adding rustc distribution directories to the tool search path.
+ for path in sess.get_tools_search_paths(false) {
+ cmd.arg({
+ let mut arg = OsString::from("-B");
+ arg.push(path.join("gcc-ld"));
+ arg
+ });
+ }
+ // Implement the "linker flavor" part of -Zgcc-ld
+ // by asking cc to use some kind of lld.
+ cmd.arg("-fuse-ld=lld");
+ if sess.target.lld_flavor != LldFlavor::Ld {
+ // Tell clang to use a non-default LLD flavor.
+ // Gcc doesn't understand the target option, but we currently assume
+ // that gcc is not used for Apple and Wasm targets (#97402).
+ cmd.arg(format!("--target={}", sess.target.llvm_target));
+ }
}
}
} else {
// to the linker args construction.
assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
match flavor {
- LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
- Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
- }
- LinkerFlavor::Em => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::Gcc => {
Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: false })
as Box<dyn Linker>
}
-
+ LinkerFlavor::Ld if sess.target.os == "l4re" => {
+ Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
+ }
LinkerFlavor::Lld(LldFlavor::Ld)
| LinkerFlavor::Lld(LldFlavor::Ld64)
| LinkerFlavor::Ld => {
Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: true })
as Box<dyn Linker>
}
-
+ LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
+ Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
+ }
LinkerFlavor::Lld(LldFlavor::Wasm) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
-
- LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
-
- LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
-
- LinkerFlavor::L4Bender => Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>,
+ LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
+ LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
+ LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
}
}
let main_llfn = cx.get_fn_addr(instance);
- let use_start_lang_item = EntryFnType::Start != entry_type;
- let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, use_start_lang_item);
+ let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, entry_type);
return Some(entry_fn);
fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
cx: &'a Bx::CodegenCx,
rust_main: Bx::Value,
rust_main_def_id: DefId,
- use_start_lang_item: bool,
+ entry_type: EntryFnType,
) -> Bx::Function {
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
// depending on whether the target needs `argc` and `argv` to be passed in.
let i8pp_ty = cx.type_ptr_to(cx.type_i8p());
let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx);
- let (start_fn, start_ty, args) = if use_start_lang_item {
+ let (start_fn, start_ty, args) = if let EntryFnType::Main { sigpipe } = entry_type {
let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
let start_fn = cx.get_fn_addr(
ty::Instance::resolve(
.unwrap()
.unwrap(),
);
- let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, i8pp_ty], isize_ty);
- (start_fn, start_ty, vec![rust_main, arg_argc, arg_argv])
+
+ let i8_ty = cx.type_i8();
+ let arg_sigpipe = bx.const_u8(sigpipe);
+
+ let start_ty =
+ cx.type_func(&[cx.val_ty(rust_main), isize_ty, i8pp_ty, i8_ty], isize_ty);
+ (start_fn, start_ty, vec![rust_main, arg_argc, arg_argv, arg_sigpipe])
} else {
debug!("using user-defined start fn");
let start_ty = cx.type_func(&[isize_ty, i8pp_ty], isize_ty);
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::Idx;
-use rustc_middle::mir::AssertKind;
-use rustc_middle::mir::{self, SwitchTargets};
+use rustc_middle::mir::{self, AssertKind, SwitchTargets};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty, TypeVisitable};
}
}
-#[instrument(skip(tcx), level = "debug")]
+#[instrument(skip(tcx), level = "debug", ret)]
pub(crate) fn turn_into_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
constant: ConstAlloc<'tcx>,
);
// Turn this into a proper constant.
- let const_val = op_to_const(&ecx, &mplace.into());
- debug!(?const_val);
-
- const_val
+ op_to_const(&ecx, &mplace.into())
}
#[instrument(skip(tcx), level = "debug")]
// All `#[rustc_do_not_const_check]` functions should be hooked here.
let def_id = instance.def_id();
- 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(),
- ));
- }
- } else if Some(def_id) == self.tcx.lang_items().panic_display()
+ if Some(def_id) == self.tcx.lang_items().panic_display()
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
{
// &str or &&str
(unsized_inner_ty, num_elems)
}
-#[instrument(skip(ecx), level = "debug")]
+#[instrument(skip(ecx), level = "debug", ret)]
fn create_pointee_place<'tcx>(
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
ty: Ty<'tcx>,
let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap();
debug!(?ptr);
- let place = MPlaceTy::from_aligned_ptr_with_meta(
+ MPlaceTy::from_aligned_ptr_with_meta(
ptr.into(),
layout,
MemPlaceMeta::Meta(Scalar::from_machine_usize(num_elems as u64, &tcx)),
- );
- debug!(?place);
-
- place
+ )
} else {
create_mplace_from_layout(ecx, ty)
}
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
/// construction has finished.
// FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
-#[instrument(skip(tcx), level = "debug")]
+#[instrument(skip(tcx), level = "debug", ret)]
pub fn valtree_to_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
dump_place(&ecx, place.into());
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
- let const_val = match ty.kind() {
+ match ty.kind() {
ty::Ref(_, _, _) => {
let ref_place = place.to_ref(&tcx);
let imm =
op_to_const(&ecx, &imm.into())
}
_ => op_to_const(&ecx, &place.into()),
- };
- debug!(?const_val);
-
- const_val
+ }
}
ty::Never
| ty::Error(_)
/// tracks where in the value we are and thus can show much better error messages.
/// Any errors here would anyway be turned into `const_err` lints, whereas validation failures
/// are hard errors.
-#[tracing::instrument(level = "debug", skip(ecx))]
+#[instrument(level = "debug", skip(ecx))]
pub fn intern_const_alloc_recursive<
'mir,
'tcx: 'mir,
use std::fmt::Debug;
use std::hash::Hash;
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_middle::mir;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::DefId;
kind: Option<MemoryKind<Self::MemoryKind>>,
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra>>>;
+ fn eval_inline_asm(
+ _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+ _template: &'tcx [InlineAsmTemplatePiece],
+ _operands: &[mir::InlineAsmOperand<'tcx>],
+ _options: InlineAsmOptions,
+ ) -> InterpResult<'tcx> {
+ throw_unsup_format!("inline assembly is not supported")
+ }
+
/// Hook for performing extra checks on a memory read access.
///
/// Takes read-only access to the allocation so we can keep all the memory read
use std::borrow::Cow;
+use rustc_ast::ast::InlineAsmOptions;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
use rustc_middle::ty::Instance;
use rustc_middle::{
terminator.kind
),
- // Inline assembly can't be interpreted.
- InlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
+ InlineAsm { template, ref operands, options, destination, .. } => {
+ M::eval_inline_asm(self, template, operands, options)?;
+ if options.contains(InlineAsmOptions::NORETURN) {
+ throw_ub_format!("returned from noreturn inline assembly");
+ }
+ self.go_to_block(
+ destination
+ .expect("InlineAsm terminators without noreturn must have a destination"),
+ )
+ }
}
Ok(())
//! to be const-safe.
use std::convert::TryFrom;
-use std::fmt::Write;
+use std::fmt::{Display, Write};
use std::num::NonZeroUsize;
use rustc_ast::Mutability;
fn read_immediate(
&self,
op: &OpTy<'tcx, M::Provenance>,
- expected: &str,
+ expected: impl Display,
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
Ok(try_validation!(
self.ecx.read_immediate(op),
fn read_scalar(
&self,
op: &OpTy<'tcx, M::Provenance>,
- expected: &str,
+ expected: impl Display,
) -> InterpResult<'tcx, Scalar<M::Provenance>> {
Ok(self.read_immediate(op, expected)?.to_scalar())
}
value: &OpTy<'tcx, M::Provenance>,
kind: &str,
) -> InterpResult<'tcx> {
- let place = self.ecx.ref_to_mplace(&self.read_immediate(value, &format!("a {kind}"))?)?;
+ let place =
+ self.ecx.ref_to_mplace(&self.read_immediate(value, format_args!("a {kind}"))?)?;
// Handle wide pointers.
// Check metadata early, for better diagnostics
if place.layout.is_unsized() {
if (src, dest).has_opaque_types() {
return true;
}
- // Normalize projections and things like that.
- let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
- let src = self.tcx.normalize_erasing_regions(param_env, src);
- let dest = self.tcx.normalize_erasing_regions(param_env, dest);
+ // Normalize projections and things like that.
// Type-changing assignments can happen when subtyping is used. While
// all normal lifetimes are erased, higher-ranked types with their
// late-bound lifetimes are still around and can lead to type
// differences. So we compare ignoring lifetimes.
- equal_up_to_regions(self.tcx, param_env, src, dest)
+
+ // First, try with reveal_all. This might not work in some cases, as the predicates
+ // can be cleared in reveal_all mode. We try the reveal first anyways as it is used
+ // by some other passes like inlining as well.
+ let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
+ if equal_up_to_regions(self.tcx, param_env, src, dest) {
+ return true;
+ }
+
+ // If this fails, we can try it without the reveal.
+ equal_up_to_regions(self.tcx, self.param_env, src, dest)
}
}
crate-type = ["dylib"]
[dependencies]
-tracing = { version = "0.1.28" }
+tracing = { version = "0.1.35" }
serde_json = "1.0.59"
rustc_log = { path = "../rustc_log" }
rustc_middle = { path = "../rustc_middle" }
.suggestion = consider restricting its visibility
.help = or consider exporting it for use by other crates
+lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name
+ .help = was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}`
+ .help = was set with `--cfg` but isn't in the `--check-cfg` expected values
+
lint_builtin_type_alias_bounds_help = use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases
lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases
--- /dev/null
+metadata_rlib_required =
+ crate `{$crate_name}` required to be available in rlib format, but was not found in this form
+
+metadata_lib_required =
+ crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+
+metadata_crate_dep_multiple =
+ cannot satisfy dependencies so `{$crate_name}` only shows up once
+ .help = having upstream crates all available in one format will likely make this go away
+
+metadata_two_panic_runtimes =
+ cannot link together two panic runtimes: {$prev_name} and {$cur_name}
+
+metadata_bad_panic_strategy =
+ the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}`
+
+metadata_required_panic_strategy =
+ the crate `{$crate_name}` requires panic strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
+
+metadata_incompatible_panic_in_drop_strategy =
+ the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
+
+metadata_multiple_names_in_link =
+ multiple `name` arguments in a single `#[link]` attribute
+
+metadata_multiple_kinds_in_link =
+ multiple `kind` arguments in a single `#[link]` attribute
+
+metadata_link_name_form =
+ link name must be of the form `name = "string"`
+
+metadata_link_kind_form =
+ link kind must be of the form `kind = "string"`
+
+metadata_link_modifiers_form =
+ link modifiers must be of the form `modifiers = "string"`
+
+metadata_link_cfg_form =
+ link cfg must be of the form `cfg(/* predicate */)`
+
+metadata_wasm_import_form =
+ wasm import module must be of the form `wasm_import_module = "string"`
+
+metadata_empty_link_name =
+ link name must not be empty
+ .label = empty link name
+
+metadata_link_framework_apple =
+ link kind `framework` is only supported on Apple targets
+
+metadata_framework_only_windows =
+ link kind `raw-dylib` is only supported on Windows targets
+
+metadata_unknown_link_kind =
+ unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib
+ .label = unknown link kind
+
+metadata_multiple_link_modifiers =
+ multiple `modifiers` arguments in a single `#[link]` attribute
+
+metadata_multiple_cfgs =
+ multiple `cfg` arguments in a single `#[link]` attribute
+
+metadata_link_cfg_single_predicate =
+ link cfg must have a single predicate argument
+
+metadata_multiple_wasm_import =
+ multiple `wasm_import_module` arguments in a single `#[link]` attribute
+
+metadata_unexpected_link_arg =
+ unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
+
+metadata_invalid_link_modifier =
+ invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
+
+metadata_multiple_modifiers =
+ multiple `{$modifier}` modifiers in a single `modifiers` argument
+
+metadata_bundle_needs_static =
+ linking modifier `bundle` is only compatible with `static` linking kind
+
+metadata_whole_archive_needs_static =
+ linking modifier `whole-archive` is only compatible with `static` linking kind
+
+metadata_as_needed_compatibility =
+ linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
+
+metadata_unknown_link_modifier =
+ unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
+
+metadata_incompatible_wasm_link =
+ `wasm_import_module` is incompatible with other arguments in `#[link]` attributes
+
+metadata_link_requires_name =
+ `#[link]` attribute requires a `name = "string"` argument
+ .label = missing `name` argument
+
+metadata_raw_dylib_no_nul =
+ link name must not contain NUL characters if link kind is `raw-dylib`
+
+metadata_link_ordinal_raw_dylib =
+ `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+
+metadata_lib_framework_apple =
+ library kind `framework` is only supported on Apple targets
+
+metadata_empty_renaming_target =
+ an empty renaming target was specified for library `{$lib_name}`
+
+metadata_renaming_no_link =
+ renaming of the library `{$lib_name}` was specified, however this crate contains no `#[link(...)]` attributes referencing this library
+
+metadata_multiple_renamings =
+ multiple renamings were specified for library `{$lib_name}`
+
+metadata_no_link_mod_override =
+ overriding linking modifiers from command line is not supported
+
+metadata_unsupported_abi_i686 =
+ ABI not supported by `#[link(kind = "raw-dylib")]` on i686
+
+metadata_unsupported_abi =
+ ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
+
+metadata_fail_create_file_encoder =
+ failed to create file encoder: {$err}
+
+metadata_fail_seek_file =
+ failed to seek the file: {$err}
+
+metadata_fail_write_file =
+ failed to write to the file: {$err}
+
+metadata_crate_not_panic_runtime =
+ the crate `{$crate_name}` is not a panic runtime
+
+metadata_no_panic_strategy =
+ the crate `{$crate_name}` does not have the panic strategy `{$strategy}`
+
+metadata_profiler_builtins_needs_core =
+ `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]`
+
+metadata_not_profiler_runtime =
+ the crate `{$crate_name}` is not a profiler runtime
+
+metadata_no_multiple_global_alloc =
+ cannot define multiple global allocators
+ .label = cannot define a new global allocator
+
+metadata_prev_global_alloc =
+ previous global allocator defined here
+
+metadata_conflicting_global_alloc =
+ the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
+
+metadata_global_alloc_required =
+ no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
+
+metadata_no_transitive_needs_dep =
+ the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}`
+
+metadata_failed_write_error =
+ failed to write {$filename}: {$err}
+
+metadata_failed_create_tempdir =
+ couldn't create a temp dir: {$err}
+
+metadata_failed_create_file =
+ failed to create the file {$filename}: {$err}
+
+metadata_failed_create_encoded_metadata =
+ failed to create encoded metadata from file: {$err}
+
+metadata_non_ascii_name =
+ cannot load a crate with a non-ascii name `{$crate_name}`
+
+metadata_extern_location_not_exist =
+ extern location for {$crate_name} does not exist: {$location}
+
+metadata_extern_location_not_file =
+ extern location for {$crate_name} is not a file: {$location}
+
+metadata_multiple_candidates =
+ multiple {$flavor} candidates for `{$crate_name}` found
+
+metadata_multiple_matching_crates =
+ multiple matching crates for `{$crate_name}`
+ .note = candidates:{$candidates}
+
+metadata_symbol_conflicts_current =
+ the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two.
+
+metadata_symbol_conflicts_others =
+ found two different crates with name `{$crate_name}` that are not distinguished by differing `-C metadata`. This will result in symbol conflicts between the two.
+
+metadata_stable_crate_id_collision =
+ found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values.
+
+metadata_dl_error =
+ {$err}
+
+metadata_newer_crate_version =
+ found possibly newer version of crate `{$crate_name}`{$add_info}
+ .note = perhaps that crate needs to be recompiled?
+
+metadata_found_crate_versions =
+ the following crate versions were found:{$found_crates}
+
+metadata_no_crate_with_triple =
+ couldn't find crate `{$crate_name}` with expected target triple {$locator_triple}{$add_info}
+
+metadata_found_staticlib =
+ found staticlib `{$crate_name}` instead of rlib or dylib{$add_info}
+ .help = please recompile that crate using --crate-type lib
+
+metadata_incompatible_rustc =
+ found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info}
+ .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first)
+
+metadata_invalid_meta_files =
+ found invalid metadata files for crate `{$crate_name}`{$add_info}
+
+metadata_cannot_find_crate =
+ can't find crate for `{$crate_name}`{$add_info}
+
+metadata_no_dylib_plugin =
+ plugin `{$crate_name}` only found in rlib format, but must be available in dylib format
+
+metadata_target_not_installed =
+ the `{$locator_triple}` target may not be installed
+
+metadata_target_no_std_support =
+ the `{$locator_triple}` target may not support the standard library
+
+metadata_consider_downloading_target =
+ consider downloading the target with `rustup target add {$locator_triple}`
+
+metadata_std_required =
+ `std` is required by `{$current_crate}` because it does not declare `#![no_std]`
+
+metadata_consider_building_std =
+ consider building the standard library from source with `cargo build -Zbuild-std`
+
+metadata_compiler_missing_profiler =
+ the compiler may have been built without the profiler runtime
+
+metadata_install_missing_components =
+ maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`
+
+metadata_cant_find_crate =
+ can't find crate
+
+metadata_crate_location_unknown_type =
+ extern location for {$crate_name} is of an unknown type: {$path}
+
+metadata_lib_filename_form =
+ file name should be lib*.rlib or {dll_prefix}*.{dll_suffix}
+
+metadata_multiple_import_name_type =
+ multiple `import_name_type` arguments in a single `#[link]` attribute
+
+metadata_import_name_type_form =
+ import name type must be of the form `import_name_type = "string"`
+
+metadata_import_name_type_x86 =
+ import name type is only supported on x86
+
+metadata_unknown_import_name_type =
+ unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated
+
+metadata_import_name_type_raw =
+ import name type can only be used with link kind `raw-dylib`
.label = can't leak {$vis_descr} {$kind}
.visibility_label = `{$descr}` declared as {$vis_descr}
+privacy_report_access_level = {$descr}
+
privacy_from_private_dep_in_public_interface =
{$kind} `{$descr}` from private dependency '{$krate}' in public interface
--- /dev/null
+trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}
+
+trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
+
+trait_selection_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}`
+ .label = deref recursion limit reached
+ .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
+
+trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
+ .label = empty on-clause here
+
+trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]`
+ .label = invalid on-clause here
+
+trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value
+ .label = expected value here
+ .note = eg `#[rustc_on_unimplemented(message="foo")]`
+
+trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc ->
+ [none] {""}
+ *[default] {" "}for type `{$self_desc}`
+ }:
+ .negative_implementation_here = negative implementation here
+ .negative_implementation_in_crate = negative implementation in crate `{$negative_impl_cname}`
+ .positive_implementation_here = positive implementation here
+ .positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}`
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
+#[macro_use]
+extern crate tracing;
+
use fluent_bundle::FluentResource;
use fluent_syntax::parser::ParserError;
use rustc_data_structures::sync::Lrc;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
-use tracing::{instrument, trace};
#[cfg(not(parallel_compiler))]
use std::cell::LazyCell as Lazy;
lint => "../locales/en-US/lint.ftl",
middle => "../locales/en-US/middle.ftl",
monomorphize => "../locales/en-US/monomorphize.ftl",
+ metadata => "../locales/en-US/metadata.ftl",
parser => "../locales/en-US/parser.ftl",
passes => "../locales/en-US/passes.ftl",
plugin_impl => "../locales/en-US/plugin_impl.ftl",
privacy => "../locales/en-US/privacy.ftl",
query_system => "../locales/en-US/query_system.ftl",
+ trait_selection => "../locales/en-US/trait_selection.ftl",
save_analysis => "../locales/en-US/save_analysis.ftl",
ty_utils => "../locales/en-US/ty_utils.ftl",
typeck => "../locales/en-US/typeck.ftl",
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_hir = { path = "../rustc_hir" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
+rustc_target = { path = "../rustc_target" }
unicode-width = "0.1.4"
atty = "0.2"
termcolor = "1.0"
annotate-snippets = "0.9"
termize = "0.1.1"
-serde = { version = "1.0.125", features = ["derive"] }
+serde = { version = "1.0.125", features = [ "derive" ] }
serde_json = "1.0.59"
[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["handleapi", "synchapi", "winbase"] }
+winapi = { version = "0.3", features = [ "handleapi", "synchapi", "winbase" ] }
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
use rustc_span::{edition::Edition, Span, DUMMY_SP};
+use rustc_target::spec::PanicStrategy;
use std::borrow::Cow;
use std::fmt;
use std::hash::{Hash, Hasher};
}
}
+impl IntoDiagnosticArg for PanicStrategy {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string()))
+ }
+}
+
impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
fn into(self) -> FluentValue<'source> {
match self {
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::thread::panicking;
-use tracing::debug;
/// Used for emitting structured error messages and other diagnostic information.
///
use std::path::Path;
use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream};
use termcolor::{Buffer, Color, WriteColor};
-use tracing::*;
/// Default column width, used in tests and when terminal dimensions cannot be determined.
const DEFAULT_COLUMN_WIDTH: usize = 140;
ex: P<ast::Expr>,
) -> ast::Stmt {
let pat = if mutbl {
- let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mut);
- self.pat_ident_binding_mode(sp, ident, binding_mode)
+ self.pat_ident_binding_mode(sp, ident, ast::BindingAnnotation::MUT)
} else {
self.pat_ident(sp, ident)
};
self.pat(span, PatKind::Lit(expr))
}
pub fn pat_ident(&self, span: Span, ident: Ident) -> P<ast::Pat> {
- let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Not);
- self.pat_ident_binding_mode(span, ident, binding_mode)
+ self.pat_ident_binding_mode(span, ident, ast::BindingAnnotation::NONE)
}
pub fn pat_ident_binding_mode(
&self,
span: Span,
ident: Ident,
- bm: ast::BindingMode,
+ ann: ast::BindingAnnotation,
) -> P<ast::Pat> {
- let pat = PatKind::Ident(bm, ident.with_span_pos(span), None);
+ let pat = PatKind::Ident(ann, ident.with_span_pos(span), None);
self.pat(span, pat)
}
pub fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat> {
#[macro_use]
extern crate rustc_macros;
+#[macro_use]
+extern crate tracing;
+
extern crate proc_macro as pm;
mod placeholders;
use std::borrow::Cow;
use std::collections::hash_map::Entry;
use std::{mem, slice};
-use tracing::debug;
pub(crate) struct ParserAnyMacro<'a> {
parser: Parser<'a>,
/// Allows creation of instances of a struct by moving fields that have
/// not changed from prior instances of the same struct (RFC #2528)
(active, type_changing_struct_update, "1.58.0", Some(86555), None),
+ /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
+ (active, unix_sigpipe, "CURRENT_RUSTC_VERSION", Some(97889), None),
/// Allows unsized fn parameters.
(active, unsized_fn_params, "1.49.0", Some(48055), None),
/// Allows unsized rvalues at arguments and parameters.
),
// Entry point:
+ gated!(unix_sigpipe, Normal, template!(Word, NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing, experimental!(unix_sigpipe)),
ungated!(start, Normal, template!(Word), WarnFollowing),
ungated!(no_start, CrateLevel, template!(Word), WarnFollowing),
ungated!(no_main, CrateLevel, template!(Word), WarnFollowing),
// Internal attributes, Testing:
// ==========================================================================
+ rustc_attr!(TEST, rustc_access_level, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local)
}
+pub fn is_valid_for_get_attr(name: Symbol) -> bool {
+ BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| match attr.duplicates {
+ WarnFollowing | ErrorFollowing | ErrorPreceding | FutureWarnFollowing
+ | FutureWarnPreceding => true,
+ DuplicatesOk | WarnFollowingWordOnly => false,
+ })
+}
+
pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
LazyLock::new(|| {
let mut map = FxHashMap::default();
pub use builtin_attrs::AttributeDuplicates;
pub use builtin_attrs::{
deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local,
- AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg,
- BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
+ is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute,
+ GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
};
pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
///
/// **Belongs to the type namespace.**
PrimTy(hir::PrimTy),
+
/// The `Self` type, optionally with the [`DefId`] of the trait it belongs to and
/// optionally with the [`DefId`] of the item introducing the `Self` type alias.
///
/// const fn baz<T>() -> usize { 10 }
/// ```
/// We do however allow `Self` in repeat expression even if it is generic to not break code
- /// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint:
+ /// which already works on stable while causing the `const_evaluatable_unchecked` future compat
+ /// lint:
/// ```
/// fn foo<T>() {
/// let _bar = [1_u8; std::mem::size_of::<*mut T>()];
/// from mentioning generics (i.e. when used in an anonymous constant).
alias_to: Option<(DefId, bool)>,
},
+
/// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`.
///
/// **Belongs to the type namespace.**
///
/// *See also [`Res::SelfTy`].*
SelfCtor(DefId),
+
/// A local variable or function parameter.
///
/// **Belongs to the value namespace.**
use std::fmt::{self, Write};
use std::hash::Hash;
-use tracing::debug;
/// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa.
/// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey`
use rustc_ast as ast;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy};
-pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
+pub use rustc_ast::{BindingAnnotation, BorrowKind, ByRef, ImplPolarity, IsAuto};
pub use rustc_ast::{CaptureBy, Movability, Mutability};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_data_structures::fingerprint::Fingerprint;
pub struct PathSegment<'hir> {
/// The identifier portion of this path segment.
pub ident: Ident,
- // `id` and `res` are optional. We currently only use these in save-analysis,
- // any path segments without these will not have save-analysis info and
- // therefore will not have 'jump to def' in IDEs, but otherwise will not be
- // affected. (In general, we don't bother to get the defs for synthesized
- // segments, only for segments which have come from the AST).
- pub hir_id: Option<HirId>,
- pub res: Option<Res>,
+ pub hir_id: HirId,
+ pub res: Res,
/// Type/lifetime parameters attached to this path. They come in
/// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
impl<'hir> PathSegment<'hir> {
/// Converts an identifier to the corresponding segment.
- pub fn from_ident(ident: Ident) -> PathSegment<'hir> {
- PathSegment { ident, hir_id: None, res: None, infer_args: true, args: None }
+ pub fn new(ident: Ident, hir_id: HirId, res: Res) -> PathSegment<'hir> {
+ PathSegment { ident, hir_id, res, infer_args: true, args: None }
}
pub fn invalid() -> Self {
- Self::from_ident(Ident::empty())
+ Self::new(Ident::empty(), HirId::INVALID, Res::Err)
}
pub fn args(&self) -> &GenericArgs<'hir> {
#[derive(Debug, HashStable_Generic)]
pub enum GenericArg<'hir> {
Lifetime(Lifetime),
- Type(Ty<'hir>),
+ Type(&'hir Ty<'hir>),
Const(ConstArg),
Infer(InferArg),
}
}
}
- pub fn id(&self) -> HirId {
+ pub fn hir_id(&self) -> HirId {
match self {
GenericArg::Lifetime(l) => l.hir_id,
GenericArg::Type(t) => t.hir_id,
pub span: Span,
}
-/// Explicit binding annotations given in the HIR for a binding. Note
-/// that this is not the final binding *mode* that we infer after type
-/// inference.
-#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
-pub enum BindingAnnotation {
- /// No binding annotation given: this means that the final binding mode
- /// will depend on whether we have skipped through a `&` reference
- /// when matching. For example, the `x` in `Some(x)` will have binding
- /// mode `None`; if you do `let Some(x) = &Some(22)`, it will
- /// ultimately be inferred to be by-reference.
- ///
- /// Note that implicit reference skipping is not implemented yet (#42640).
- Unannotated,
-
- /// Annotated with `mut x` -- could be either ref or not, similar to `None`.
- Mutable,
-
- /// Annotated as `ref`, like `ref x`
- Ref,
-
- /// Annotated as `ref mut x`.
- RefMut,
-}
-
#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
pub enum RangeEnd {
Included,
Semi(&'hir Expr<'hir>),
}
-/// Represents a `let` statement (i.e., `let <pat>:<ty> = <expr>;`).
+/// Represents a `let` statement (i.e., `let <pat>:<ty> = <init>;`).
#[derive(Debug, HashStable_Generic)]
pub struct Local<'hir> {
pub pat: &'hir Pat<'hir>,
#[derive(Debug, HashStable_Generic)]
pub struct Body<'hir> {
pub params: &'hir [Param<'hir>],
- pub value: Expr<'hir>,
+ pub value: &'hir Expr<'hir>,
pub generator_kind: Option<GeneratorKind>,
}
///
/// The `PathSegment` represents the method name and its generic arguments
/// (within the angle brackets).
- /// The first element of the `&[Expr]` is the expression that evaluates
+ /// The `&Expr` is the expression that evaluates
/// to the object on which the method is being called on (the receiver),
- /// and the remaining elements are the rest of the arguments.
+ /// and the `&[Expr]` is the rest of the arguments.
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
- /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d], span)`.
+ /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d], span)`.
/// The final `Span` represents the span of the function and arguments
/// (e.g. `foo::<Bar, Baz>(a, b, c, d)` in `x.foo::<Bar, Baz>(a, b, c, d)`
///
/// the `hir_id` of the `MethodCall` node itself.
///
/// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id
- MethodCall(&'hir PathSegment<'hir>, &'hir [Expr<'hir>], Span),
+ MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span),
/// A tuple (e.g., `(a, b, c, d)`).
Tup(&'hir [Expr<'hir>]),
/// A binary operation (e.g., `a + b`, `a * b`).
pub enum InlineAsmOperand<'hir> {
In {
reg: InlineAsmRegOrRegClass,
- expr: Expr<'hir>,
+ expr: &'hir Expr<'hir>,
},
Out {
reg: InlineAsmRegOrRegClass,
late: bool,
- expr: Option<Expr<'hir>>,
+ expr: Option<&'hir Expr<'hir>>,
},
InOut {
reg: InlineAsmRegOrRegClass,
late: bool,
- expr: Expr<'hir>,
+ expr: &'hir Expr<'hir>,
},
SplitInOut {
reg: InlineAsmRegOrRegClass,
late: bool,
- in_expr: Expr<'hir>,
- out_expr: Option<Expr<'hir>>,
+ in_expr: &'hir Expr<'hir>,
+ out_expr: Option<&'hir Expr<'hir>>,
},
Const {
anon_const: AnonConst,
/// A MBE macro definition (`macro_rules!` or `macro`).
Macro(ast::MacroDef, MacroKind),
/// A module.
- Mod(Mod<'hir>),
+ Mod(&'hir Mod<'hir>),
/// An external module, e.g. `extern { .. }`.
ForeignMod { abi: Abi, items: &'hir [ForeignItemRef] },
/// Module-level inline assembly (from `global_asm!`).
mod size_asserts {
use super::*;
// These are in alphabetical order, which is easy to maintain.
- static_assert_size!(Block<'static>, 48);
- static_assert_size!(Expr<'static>, 56);
- static_assert_size!(ForeignItem<'static>, 72);
+ static_assert_size!(Block<'_>, 48);
+ static_assert_size!(Body<'_>, 32);
+ static_assert_size!(Expr<'_>, 64);
+ static_assert_size!(ExprKind<'_>, 48);
+ static_assert_size!(FnDecl<'_>, 40);
+ static_assert_size!(ForeignItem<'_>, 72);
+ static_assert_size!(ForeignItemKind<'_>, 40);
+ static_assert_size!(GenericArg<'_>, 40);
static_assert_size!(GenericBound<'_>, 48);
- static_assert_size!(Generics<'static>, 56);
- static_assert_size!(ImplItem<'static>, 88);
- static_assert_size!(Impl<'static>, 80);
- static_assert_size!(Item<'static>, 80);
- static_assert_size!(Pat<'static>, 88);
- static_assert_size!(QPath<'static>, 24);
- static_assert_size!(TraitItem<'static>, 96);
- static_assert_size!(Ty<'static>, 72);
+ static_assert_size!(Generics<'_>, 56);
+ static_assert_size!(Impl<'_>, 80);
+ static_assert_size!(ImplItem<'_>, 88);
+ static_assert_size!(ImplItemKind<'_>, 40);
+ static_assert_size!(Item<'_>, 80);
+ static_assert_size!(ItemKind<'_>, 48);
+ static_assert_size!(Local<'_>, 64);
+ static_assert_size!(Param<'_>, 32);
+ static_assert_size!(Pat<'_>, 88);
+ static_assert_size!(PatKind<'_>, 64);
+ static_assert_size!(Path<'_>, 48);
+ static_assert_size!(PathSegment<'_>, 56);
+ static_assert_size!(QPath<'_>, 24);
+ static_assert_size!(Stmt<'_>, 32);
+ static_assert_size!(StmtKind<'_>, 16);
+ static_assert_size!(TraitItem<'_>, 96);
+ static_assert_size!(TraitItemKind<'_>, 56);
+ static_assert_size!(Ty<'_>, 72);
+ static_assert_size!(TyKind<'_>, 56);
}
}
impl HirId {
+ /// Signal local id which should never be used.
+ pub const INVALID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::INVALID };
+
#[inline]
pub fn expect_owner(self) -> LocalDefId {
assert_eq!(self.local_id.index(), 0);
segment: &'v PathSegment<'v>,
) {
visitor.visit_ident(segment.ident);
- walk_list!(visitor, visit_id, segment.hir_id);
+ visitor.visit_id(segment.hir_id);
if let Some(ref args) = segment.args {
visitor.visit_generic_args(path_span, args);
}
visitor.visit_expr(callee_expression);
walk_list!(visitor, visit_expr, arguments);
}
- ExprKind::MethodCall(ref segment, arguments, _) => {
+ ExprKind::MethodCall(ref segment, receiver, arguments, _) => {
visitor.visit_path_segment(expression.span, segment);
+ visitor.visit_expr(receiver);
walk_list!(visitor, visit_expr, arguments);
}
ExprKind::Binary(_, ref left_expression, ref right_expression) => {
DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1);
// language items relating to transmutability
- TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(6);
+ TransmuteOpts, sym::transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0);
+ TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(3);
Add(Op), sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1);
Sub(Op), sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1);
DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1);
Oom, sym::oom, oom, Target::Fn, GenericRequirement::None;
AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None;
- ConstEvalSelect, sym::const_eval_select, const_eval_select, Target::Fn, GenericRequirement::Exact(4);
- ConstConstEvalSelect, sym::const_eval_select_ct,const_eval_select_ct, Target::Fn, GenericRequirement::Exact(4);
Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1);
#[macro_use]
extern crate rustc_macros;
+#[macro_use]
+extern crate tracing;
+
#[macro_use]
extern crate rustc_data_structures;
use crate::def::{CtorOf, DefKind, Res};
use crate::def_id::DefId;
-use crate::hir::{self, HirId, PatKind};
+use crate::hir::{self, BindingAnnotation, ByRef, HirId, PatKind};
use rustc_data_structures::fx::FxHashSet;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::Ident;
pub fn simple_ident(&self) -> Option<Ident> {
match self.kind {
- PatKind::Binding(
- hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
- _,
- ident,
- None,
- ) => Some(ident),
+ PatKind::Binding(BindingAnnotation(ByRef::No, _), _, ident, None) => Some(ident),
_ => None,
}
}
pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
let mut result = None;
self.each_binding(|annotation, _, _, _| match annotation {
- hir::BindingAnnotation::Ref => match result {
+ hir::BindingAnnotation::REF => match result {
None | Some(hir::Mutability::Not) => result = Some(hir::Mutability::Not),
_ => {}
},
- hir::BindingAnnotation::RefMut => result = Some(hir::Mutability::Mut),
+ hir::BindingAnnotation::REF_MUT => result = Some(hir::Mutability::Mut),
_ => {}
});
result
use rustc_ast_pretty::pprust::{Comments, PrintState};
use rustc_hir as hir;
use rustc_hir::LifetimeParamKind;
-use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
+use rustc_hir::{
+ BindingAnnotation, ByRef, GenericArg, GenericParam, GenericParamKind, Mutability, Node, Term,
+};
use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol};
self.print_call_post(args)
}
- fn print_expr_method_call(&mut self, segment: &hir::PathSegment<'_>, args: &[hir::Expr<'_>]) {
- let base_args = &args[1..];
- self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
+ fn print_expr_method_call(
+ &mut self,
+ segment: &hir::PathSegment<'_>,
+ receiver: &hir::Expr<'_>,
+ args: &[hir::Expr<'_>],
+ ) {
+ let base_args = args;
+ self.print_expr_maybe_paren(&receiver, parser::PREC_POSTFIX);
self.word(".");
self.print_ident(segment.ident);
let generic_args = segment.args();
if !generic_args.args.is_empty() || !generic_args.bindings.is_empty() {
- self.print_generic_args(generic_args, segment.infer_args, true);
+ self.print_generic_args(generic_args, true);
}
self.print_call_post(base_args)
hir::ExprKind::Call(func, args) => {
self.print_expr_call(func, args);
}
- hir::ExprKind::MethodCall(segment, args, _) => {
- self.print_expr_method_call(segment, args);
+ hir::ExprKind::MethodCall(segment, receiver, args, _) => {
+ self.print_expr_method_call(segment, receiver, args);
}
hir::ExprKind::Binary(op, lhs, rhs) => {
self.print_expr_binary(op, lhs, rhs);
}
if segment.ident.name != kw::PathRoot {
self.print_ident(segment.ident);
- self.print_generic_args(segment.args(), segment.infer_args, colons_before_params);
+ self.print_generic_args(segment.args(), colons_before_params);
}
}
}
pub fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) {
if segment.ident.name != kw::PathRoot {
self.print_ident(segment.ident);
- self.print_generic_args(segment.args(), segment.infer_args, false);
+ self.print_generic_args(segment.args(), false);
}
}
}
if segment.ident.name != kw::PathRoot {
self.print_ident(segment.ident);
- self.print_generic_args(
- segment.args(),
- segment.infer_args,
- colons_before_params,
- );
+ self.print_generic_args(segment.args(), colons_before_params);
}
}
self.word("::");
let item_segment = path.segments.last().unwrap();
self.print_ident(item_segment.ident);
- self.print_generic_args(
- item_segment.args(),
- item_segment.infer_args,
- colons_before_params,
- )
+ self.print_generic_args(item_segment.args(), colons_before_params)
}
hir::QPath::TypeRelative(qself, item_segment) => {
// If we've got a compound-qualified-path, let's push an additional pair of angle
self.word("::");
self.print_ident(item_segment.ident);
- self.print_generic_args(
- item_segment.args(),
- item_segment.infer_args,
- colons_before_params,
- )
+ self.print_generic_args(item_segment.args(), colons_before_params)
}
hir::QPath::LangItem(lang_item, span, _) => {
self.word("#[lang = \"");
fn print_generic_args(
&mut self,
generic_args: &hir::GenericArgs<'_>,
- infer_args: bool,
colons_before_params: bool,
) {
if generic_args.parenthesized {
);
}
- // FIXME(eddyb): this would leak into error messages (e.g.,
- // "non-exhaustive patterns: `Some::<..>(_)` not covered").
- if infer_args && false {
- start_or_comma(self);
- self.word("..");
- }
-
for binding in generic_args.bindings {
start_or_comma(self);
self.print_type_binding(binding);
pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
self.print_ident(binding.ident);
- self.print_generic_args(binding.gen_args, false, false);
+ self.print_generic_args(binding.gen_args, false);
self.space();
match binding.kind {
hir::TypeBindingKind::Equality { ref term } => {
// is that it doesn't matter
match pat.kind {
PatKind::Wild => self.word("_"),
- PatKind::Binding(binding_mode, _, ident, sub) => {
- match binding_mode {
- hir::BindingAnnotation::Ref => {
- self.word_nbsp("ref");
- self.print_mutability(hir::Mutability::Not, false);
- }
- hir::BindingAnnotation::RefMut => {
- self.word_nbsp("ref");
- self.print_mutability(hir::Mutability::Mut, false);
- }
- hir::BindingAnnotation::Unannotated => {}
- hir::BindingAnnotation::Mutable => {
- self.word_nbsp("mut");
- }
+ PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => {
+ if by_ref == ByRef::Yes {
+ self.word_nbsp("ref");
+ }
+ if mutbl == Mutability::Mut {
+ self.word_nbsp("mut");
}
self.print_ident(ident);
if let Some(p) = sub {
contains_exterior_struct_lit(x)
}
- hir::ExprKind::MethodCall(.., exprs, _) => {
+ hir::ExprKind::MethodCall(_, receiver, ..) => {
// `X { y: 1 }.bar(...)`
- contains_exterior_struct_lit(&exprs[0])
+ contains_exterior_struct_lit(receiver)
}
_ => false,
/// Preconditions:
///
/// - `for_vid` is a "root vid"
- #[instrument(skip(self), level = "trace")]
+ #[instrument(skip(self), level = "trace", ret)]
fn generalize(
&self,
ty: Ty<'tcx>,
cache: SsoHashMap::new(),
};
- let ty = match generalize.relate(ty, ty) {
- Ok(ty) => ty,
- Err(e) => {
- debug!(?e, "failure");
- return Err(e);
- }
- };
+ let ty = generalize.relate(ty, ty)?;
let needs_wf = generalize.needs_wf;
- trace!(?ty, ?needs_wf, "success");
Ok(Generalization { ty, needs_wf })
}
/// Result from a generalization operation. This includes
/// not only the generalized type, but also a bool flag
/// indicating whether further WF checks are needed.
+#[derive(Debug)]
struct Generalization<'tcx> {
ty: Ty<'tcx>,
Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug_assert_eq!(t, _t);
- debug!("ConstInferUnifier: t={:?}", t);
match t.kind() {
&ty::Infer(ty::TyVar(vid)) => {
.borrow_mut()
.type_variables()
.new_var(self.for_universe, origin);
- let u = self.tcx().mk_ty_var(new_var_id);
- debug!(
- "ConstInferUnifier: replacing original vid={:?} with new={:?}",
- vid, u
- );
- Ok(u)
+ Ok(self.tcx().mk_ty_var(new_var_id))
}
}
}
}
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn consts(
&mut self,
c: ty::Const<'tcx>,
_c: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
debug_assert_eq!(c, _c);
- debug!("ConstInferUnifier: c={:?}", c);
match c.kind() {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
/// the message in `secondary_span` as the primary label, and apply the message that would
/// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on
/// E0271, like `src/test/ui/issues/issue-39970.stderr`.
- #[tracing::instrument(
+ #[instrument(
level = "debug",
skip(self, diag, secondary_span, swap_secondary_and_primary, prefer_label)
)]
}
}
}
- hir::ExprKind::MethodCall(segment, _, _) => {
+ hir::ExprKind::MethodCall(segment, ..) => {
if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) {
let generics = tcx.generics_of(def_id);
let insertable: Option<_> = try {
None?
}
let substs = self.node_substs_opt(expr.hir_id)?;
- let span = tcx.hir().span(segment.hir_id?);
+ let span = tcx.hir().span(segment.hir_id);
let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
InsertableGenericArgs {
insert_span,
path.segments
.iter()
.filter_map(move |segment| {
- let res = segment.res?;
+ let res = segment.res;
let generics_def_id = tcx.res_generics_def_id(res)?;
let generics = tcx.generics_of(generics_def_id);
if generics.has_impl_trait() {
return None;
}
- let span = tcx.hir().span(segment.hir_id?);
+ let span = tcx.hir().span(segment.hir_id);
let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
Some(InsertableGenericArgs {
insert_span,
if !segment.infer_args || generics.has_impl_trait() {
None?;
}
- let span = tcx.hir().span(segment.hir_id?);
+ let span = tcx.hir().span(segment.hir_id);
let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id }
};
let generic_args = &generics.own_substs_no_defaults(tcx, substs)
[generics.own_counts().lifetimes..];
let span = match expr.kind {
- ExprKind::MethodCall(path, _, _) => path.ident.span,
+ ExprKind::MethodCall(path, ..) => path.ident.span,
_ => expr.span,
};
})
.any(|generics| generics.has_impl_trait())
};
- if let ExprKind::MethodCall(path, args, span) = expr.kind
+ if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind
&& let Some(substs) = self.node_substs_opt(expr.hir_id)
&& substs.iter().any(|arg| self.generic_arg_contains_target(arg))
&& let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
&& !has_impl_trait(def_id)
{
let successor =
- args.get(1).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
+ args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
let substs = self.infcx.resolve_vars_if_possible(substs);
self.update_infer_source(InferSource {
span: path.ident.span,
kind: InferSourceKind::FullyQualifiedMethodCall {
- receiver: args.first().unwrap(),
+ receiver,
successor,
substs,
def_id,
}
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
[segment]
- if segment
- .res
- .map(|res| {
- matches!(
- res,
- Res::SelfTy { trait_: _, alias_to: _ }
- | Res::Def(hir::def::DefKind::TyParam, _)
- )
- })
- .unwrap_or(false) =>
+ if matches!(
+ segment.res,
+ Res::SelfTy { trait_: _, alias_to: _ }
+ | Res::Def(hir::def::DefKind::TyParam, _)
+ ) =>
{
self.types.push(path.span);
}
/// For more details visit the relevant sections of the [rustc dev guide].
///
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
where
T: TypeFoldable<'tcx> + Copy,
},
};
- let result = self.tcx.replace_bound_vars_uncached(binder, delegate);
- debug!(?next_universe, ?result);
- result
+ debug!(?next_universe);
+ self.tcx.replace_bound_vars_uncached(binder, delegate)
}
/// See [RegionConstraintCollector::leak_check][1].
///
/// Neither `a` nor `b` may be an inference variable (hence the
/// term "concrete regions").
- #[instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self), ret)]
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
- let r = match (*a, *b) {
+ match (*a, *b) {
(ReLateBound(..), _) | (_, ReLateBound(..)) | (ReErased, _) | (_, ReErased) => {
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
}
self.tcx().lifetimes.re_static
}
}
- };
-
- debug!("lub_concrete_regions({:?}, {:?}) = {:?}", a, b, r);
-
- r
+ }
}
/// After expansion is complete, go and check upper bounds (i.e.,
true
}
- #[instrument(skip(self, info), level = "trace")]
+ #[instrument(skip(self, info), level = "trace", ret)]
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
self.ambient_variance = old_ambient_variance;
- debug!(?r);
-
Ok(r)
}
});
}
- #[instrument(skip(self), level = "trace")]
+ #[instrument(skip(self), level = "trace", ret)]
pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<OpaqueTyOrigin> {
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let parent_def_id = match self.defining_use_anchor {
in_definition_scope.then_some(*origin)
}
- #[instrument(skip(self), level = "trace")]
+ #[instrument(skip(self), level = "trace", ret)]
fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin {
- let origin = match self.tcx.hir().expect_item(def_id).kind {
+ match self.tcx.hir().expect_item(def_id).kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
ref itemkind => {
span_bug!(span, "weird opaque type: {:?}, {:#?}", def_id, itemkind)
}
- };
- trace!(?origin);
- origin
+ }
}
}
}
}
- #[instrument(level = "debug")]
+ #[instrument(level = "debug", ret)]
pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> {
std::mem::take(&mut self.opaque_types)
}
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty;
-#[instrument(level = "debug", skip(param_env))]
+#[instrument(level = "debug", skip(param_env), ret)]
pub fn explicit_outlives_bounds<'tcx>(
param_env: ty::ParamEnv<'tcx>,
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
self.delegate.push_verify(origin, generic, region, verify_bound);
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn projection_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,
/// like are used. This is a particular challenge since this function is invoked
/// very late in inference and hence cannot make use of the normal inference
/// machinery.
-#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+#[instrument(level = "debug", skip(tcx, param_env))]
pub fn extract_verify_if_eq<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
/// True if a (potentially higher-ranked) outlives
-#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+#[instrument(level = "debug", skip(tcx, param_env))]
pub(super) fn can_match_erased_ty<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
/// Binds the pattern variable `br` to `value`; returns an `Err` if the pattern
/// is already bound to a different value.
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn bind(
&mut self,
br: ty::BoundRegion,
// JUSTIFICATION: before session exists, only config
#[allow(rustc::bad_opt_access)]
pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
- tracing::trace!("run_compiler");
+ trace!("run_compiler");
util::run_in_thread_pool_with_globals(
config.opts.edition,
config.opts.unstable_opts.threads,
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
+#[macro_use]
+extern crate tracing;
+
mod callbacks;
mod errors;
pub mod interface;
use rustc_span::FileName;
use rustc_trait_selection::traits;
use rustc_typeck as typeck;
-use tracing::{info, warn};
use std::any::Any;
use std::cell::RefCell;
}
if sess.opts.unstable_opts.hir_stats {
- hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS");
+ hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1");
}
Ok(krate)
krate: &ast::Crate,
crate_name: &str,
) -> BoxedResolver {
- tracing::trace!("create_resolver");
+ trace!("create_resolver");
BoxedResolver::new(sess, move |sess, resolver_arenas| {
Resolver::new(sess, krate, crate_name, metadata_loader, resolver_arenas)
})
crate_name: &str,
resolver: &mut Resolver<'_>,
) -> Result<ast::Crate> {
- tracing::trace!("configure_and_expand");
+ trace!("configure_and_expand");
pre_expansion_lint(sess, lint_store, resolver.registered_tools(), &krate, crate_name);
rustc_builtin_macros::register_builtin_macros(resolver);
}
if sess.opts.unstable_opts.hir_stats {
- hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS");
+ hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS", "ast-stats-2");
}
resolver.resolve_crate(&krate);
pub fn expansion(
&self,
) -> Result<&Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> {
- tracing::trace!("expansion");
+ trace!("expansion");
self.expansion.compute(|| {
let crate_name = self.crate_name()?.peek().clone();
let (krate, lint_store) = self.register_plugins()?.take();
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::symbol::sym;
use rustc_span::SourceFileHashAlgorithm;
-use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
-use rustc_target::spec::{
- RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel,
-};
+use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
+use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
untracked!(link_args, vec![String::from("abc"), String::from("def")]);
untracked!(link_self_contained, Some(true));
untracked!(linker, Some(PathBuf::from("linker")));
- untracked!(linker_flavor, Some(LinkerFlavor::Gcc));
+ untracked!(linker_flavor, Some(LinkerFlavorCli::Gcc));
untracked!(no_stack_check, true);
untracked!(remark, Passes::Some(vec![String::from("pass1"), String::from("pass2")]));
untracked!(rpath, true);
+use info;
use libloading::Library;
use rustc_ast as ast;
use rustc_codegen_ssa::traits::CodegenBackend;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::OnceLock;
use std::thread;
-use tracing::info;
/// Function pointer type that constructs a new CodegenBackend.
pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
}
// We only care about method call expressions.
- if let hir::ExprKind::MethodCall(call, args, _) = &expr.kind {
+ if let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind {
if call.ident.name != sym::into_iter {
return;
}
};
// As this is a method call expression, we have at least one argument.
- let receiver_arg = &args[0];
let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
use crate::nonstandard_style::{method_context, MethodLateContext};
use std::fmt::Write;
-use tracing::{debug, trace};
// hardwired lints from librustc_middle
pub use rustc_session::lint::builtin::*;
== Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
{
cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
- let binding = match binding_annot {
- hir::BindingAnnotation::Unannotated => None,
- hir::BindingAnnotation::Mutable => Some("mut"),
- hir::BindingAnnotation::Ref => Some("ref"),
- hir::BindingAnnotation::RefMut => Some("ref mut"),
- };
- let suggested_ident = if let Some(binding) = binding {
- format!("{} {}", binding, ident)
- } else {
- ident.to_string()
- };
+ let suggested_ident =
+ format!("{}{}", binding_annot.prefix_str(), ident);
lint.build(fluent::lint::builtin_non_shorthand_field_patterns)
.set_arg("ident", ident.clone())
.span_suggestion(
_ => {}
}
}
- } else if let hir::ExprKind::MethodCall(_, ref args, _) = expr.kind {
+ } else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
// Find problematic calls to `MaybeUninit::assume_init`.
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
// This is a call to *some* method named `assume_init`.
// See if the `self` parameter is one of the dangerous constructors.
- if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
+ if let hir::ExprKind::Call(ref path_expr, _) = receiver.kind {
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
match cx.tcx.get_diagnostic_name(def_id) {
}
}
}
+
+declare_lint! {
+ /// The `special_module_name` lint detects module
+ /// declarations for files that have a special meaning.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// mod lib;
+ ///
+ /// fn main() {
+ /// lib::run();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Cargo recognizes `lib.rs` and `main.rs` as the root of a
+ /// library or binary crate, so declaring them as modules
+ /// will lead to miscompilation of the crate unless configured
+ /// explicitly.
+ ///
+ /// To access a library from a binary target within the same crate,
+ /// use `your_crate_name::` as the path path instead of `lib::`:
+ ///
+ /// ```rust,compile_fail
+ /// // bar/src/lib.rs
+ /// fn run() {
+ /// // ...
+ /// }
+ ///
+ /// // bar/src/main.rs
+ /// fn main() {
+ /// bar::run();
+ /// }
+ /// ```
+ ///
+ /// Binary targets cannot be used as libraries and so declaring
+ /// one as a module is not allowed.
+ pub SPECIAL_MODULE_NAME,
+ Warn,
+ "module declarations for files with a special meaning",
+}
+
+declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]);
+
+impl EarlyLintPass for SpecialModuleName {
+ fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
+ for item in &krate.items {
+ if let ast::ItemKind::Mod(
+ _,
+ ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
+ ) = item.kind
+ {
+ if item.attrs.iter().any(|a| a.has_name(sym::path)) {
+ continue;
+ }
+
+ match item.ident.name.as_str() {
+ "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
+ lint.build("found module declaration for lib.rs")
+ .note("lib.rs is the root of this crate's library target")
+ .help("to refer to it from other targets, use the library's name as the path")
+ .emit()
+ }),
+ "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
+ lint.build("found module declaration for main.rs")
+ .note("a binary crate cannot be used as library")
+ .emit()
+ }),
+ _ => continue
+ }
+ }
+ }
+ }
+}
+
+pub use rustc_session::lint::builtin::UNEXPECTED_CFGS;
+
+declare_lint_pass!(UnexpectedCfgs => [UNEXPECTED_CFGS]);
+
+impl EarlyLintPass for UnexpectedCfgs {
+ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
+ let cfg = &cx.sess().parse_sess.config;
+ let check_cfg = &cx.sess().parse_sess.check_config;
+ for &(name, value) in cfg {
+ if let Some(names_valid) = &check_cfg.names_valid {
+ if !names_valid.contains(&name) {
+ cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| {
+ diag.build(fluent::lint::builtin_unexpected_cli_config_name)
+ .help(fluent::lint::help)
+ .set_arg("name", name)
+ .emit();
+ });
+ }
+ }
+ if let Some(value) = value {
+ if let Some(values) = &check_cfg.values_valid.get(&name) {
+ if !values.contains(&value) {
+ cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| {
+ diag.build(fluent::lint::builtin_unexpected_cli_config_value)
+ .help(fluent::lint::help)
+ .set_arg("name", name)
+ .set_arg("value", value)
+ .emit();
+ });
+ }
+ }
+ }
+ }
+ }
+}
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{BytePos, Span};
use rustc_target::abi;
-use tracing::debug;
use std::cell::Cell;
use std::iter;
None => {
// 1. The tool is currently running, so this lint really doesn't exist.
// FIXME: should this handle tools that never register a lint, like rustfmt?
- tracing::debug!("lints={:?}", self.by_name.keys().collect::<Vec<_>>());
+ debug!("lints={:?}", self.by_name.keys().collect::<Vec<_>>());
let tool_prefix = format!("{}::", tool_name);
return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
self.no_lint_suggestion(&complete_name)
CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name)))
}
Some(other) => {
- tracing::debug!("got renamed lint {:?}", other);
+ debug!("got renamed lint {:?}", other);
CheckLintNameResult::NoLint(None)
}
}
if let Some(positional_arg_to_replace) = position_sp_to_replace {
let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name };
let span_to_replace = if let Ok(positional_arg_content) =
- self.sess().source_map().span_to_snippet(positional_arg_to_replace) && positional_arg_content.starts_with(":") {
+ self.sess().source_map().span_to_snippet(positional_arg_to_replace) && positional_arg_content.starts_with(':') {
positional_arg_to_replace.shrink_to_lo()
} else {
positional_arg_to_replace
use rustc_span::Span;
use std::slice;
-use tracing::debug;
macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({
$cx.pass.$f(&$cx.context, $($args),*);
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
-use tracing::debug;
declare_tool_lint! {
pub rustc::DEFAULT_HASH_TYPES,
expr: &Expr<'_>,
) -> Option<(Span, DefId, ty::subst::SubstsRef<'tcx>)> {
match expr.kind {
- ExprKind::MethodCall(segment, _, _)
+ ExprKind::MethodCall(segment, ..)
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
{
Some((segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id)))
_: rustc_hir::HirId,
) {
if let Some(segment) = path.segments.iter().nth_back(1)
- && let Some(res) = &segment.res
- && lint_ty_kind_usage(cx, res)
+ && lint_ty_kind_usage(cx, &segment.res)
{
let span = path.span.with_hi(
segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
use std::any::Any;
use std::cell::Cell;
use std::slice;
-use tracing::debug;
/// Extract the `LintStore` from the query context.
/// This function exists because we've erased `LintStore` as `dyn Any` in the context.
--- /dev/null
+use crate::{LateContext, LateLintPass, LintContext};
+use rustc_errors::{Applicability, LintDiagnosticBuilder, MultiSpan};
+use rustc_hir as hir;
+use rustc_middle::ty;
+use rustc_span::Symbol;
+
+declare_lint! {
+ /// The `let_underscore_drop` lint checks for statements which don't bind
+ /// an expression which has a non-trivial Drop implementation to anything,
+ /// causing the expression to be dropped immediately instead of at end of
+ /// scope.
+ ///
+ /// ### Example
+ /// ```
+ /// struct SomeStruct;
+ /// impl Drop for SomeStruct {
+ /// fn drop(&mut self) {
+ /// println!("Dropping SomeStruct");
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// #[warn(let_underscore_drop)]
+ /// // SomeStuct is dropped immediately instead of at end of scope,
+ /// // so "Dropping SomeStruct" is printed before "end of main".
+ /// // The order of prints would be reversed if SomeStruct was bound to
+ /// // a name (such as "_foo").
+ /// let _ = SomeStruct;
+ /// println!("end of main");
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Statements which assign an expression to an underscore causes the
+ /// expression to immediately drop instead of extending the expression's
+ /// lifetime to the end of the scope. This is usually unintended,
+ /// especially for types like `MutexGuard`, which are typically used to
+ /// lock a mutex for the duration of an entire scope.
+ ///
+ /// If you want to extend the expression's lifetime to the end of the scope,
+ /// assign an underscore-prefixed name (such as `_foo`) to the expression.
+ /// If you do actually want to drop the expression immediately, then
+ /// calling `std::mem::drop` on the expression is clearer and helps convey
+ /// intent.
+ pub LET_UNDERSCORE_DROP,
+ Allow,
+ "non-binding let on a type that implements `Drop`"
+}
+
+declare_lint! {
+ /// The `let_underscore_lock` lint checks for statements which don't bind
+ /// a mutex to anything, causing the lock to be released immediately instead
+ /// of at end of scope, which is typically incorrect.
+ ///
+ /// ### Example
+ /// ```compile_fail
+ /// use std::sync::{Arc, Mutex};
+ /// use std::thread;
+ /// let data = Arc::new(Mutex::new(0));
+ ///
+ /// thread::spawn(move || {
+ /// // The lock is immediately released instead of at the end of the
+ /// // scope, which is probably not intended.
+ /// let _ = data.lock().unwrap();
+ /// println!("doing some work");
+ /// let mut lock = data.lock().unwrap();
+ /// *lock += 1;
+ /// });
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Statements which assign an expression to an underscore causes the
+ /// expression to immediately drop instead of extending the expression's
+ /// lifetime to the end of the scope. This is usually unintended,
+ /// especially for types like `MutexGuard`, which are typically used to
+ /// lock a mutex for the duration of an entire scope.
+ ///
+ /// If you want to extend the expression's lifetime to the end of the scope,
+ /// assign an underscore-prefixed name (such as `_foo`) to the expression.
+ /// If you do actually want to drop the expression immediately, then
+ /// calling `std::mem::drop` on the expression is clearer and helps convey
+ /// intent.
+ pub LET_UNDERSCORE_LOCK,
+ Deny,
+ "non-binding let on a synchronization lock"
+}
+
+declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK]);
+
+const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [
+ rustc_span::sym::MutexGuard,
+ rustc_span::sym::RwLockReadGuard,
+ rustc_span::sym::RwLockWriteGuard,
+];
+
+impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
+ fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
+ if !matches!(local.pat.kind, hir::PatKind::Wild) {
+ return;
+ }
+ if let Some(init) = local.init {
+ let init_ty = cx.typeck_results().expr_ty(init);
+ // If the type has a trivial Drop implementation, then it doesn't
+ // matter that we drop the value immediately.
+ if !init_ty.needs_drop(cx.tcx, cx.param_env) {
+ return;
+ }
+ let is_sync_lock = match init_ty.kind() {
+ ty::Adt(adt, _) => SYNC_GUARD_SYMBOLS
+ .iter()
+ .any(|guard_symbol| cx.tcx.is_diagnostic_item(*guard_symbol, adt.did())),
+ _ => false,
+ };
+
+ if is_sync_lock {
+ let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]);
+ span.push_span_label(
+ local.pat.span,
+ "this lock is not assigned to a binding and is immediately dropped".to_string(),
+ );
+ span.push_span_label(
+ init.span,
+ "this binding will immediately drop the value assigned to it".to_string(),
+ );
+ cx.struct_span_lint(LET_UNDERSCORE_LOCK, span, |lint| {
+ build_and_emit_lint(
+ lint,
+ local,
+ init.span,
+ "non-binding let on a synchronization lock",
+ )
+ })
+ } else {
+ cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| {
+ build_and_emit_lint(
+ lint,
+ local,
+ init.span,
+ "non-binding let on a type that implements `Drop`",
+ );
+ })
+ }
+ }
+ }
+}
+
+fn build_and_emit_lint(
+ lint: LintDiagnosticBuilder<'_, ()>,
+ local: &hir::Local<'_>,
+ init_span: rustc_span::Span,
+ msg: &str,
+) {
+ lint.build(msg)
+ .span_suggestion_verbose(
+ local.pat.span,
+ "consider binding to an unused variable to avoid immediately dropping the value",
+ "_unused",
+ Applicability::MachineApplicable,
+ )
+ .multipart_suggestion(
+ "consider immediately dropping the value",
+ vec![
+ (local.span.until(init_span), "drop(".to_string()),
+ (init_span.shrink_to_hi(), ")".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ )
+ .emit();
+}
use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
-use tracing::debug;
use crate::errors::{
MalformedAttribute, MalformedAttributeSub, OverruledAttribute, OverruledAttributeSub,
extern crate rustc_middle;
#[macro_use]
extern crate rustc_session;
+#[macro_use]
+extern crate tracing;
mod array_into_iter;
pub mod builtin;
pub mod hidden_unicode_codepoints;
mod internal;
mod late;
+mod let_underscore;
mod levels;
mod methods;
mod non_ascii_idents;
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
use hidden_unicode_codepoints::*;
use internal::*;
+use let_underscore::*;
use methods::*;
use non_ascii_idents::*;
use non_fmt_panic::NonPanicFmt;
UnusedBraces: UnusedBraces,
UnusedImportBraces: UnusedImportBraces,
UnsafeCode: UnsafeCode,
+ SpecialModuleName: SpecialModuleName,
AnonymousParameters: AnonymousParameters,
EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
NonCamelCaseTypes: NonCamelCaseTypes,
IncompleteFeatures: IncompleteFeatures,
RedundantSemicolons: RedundantSemicolons,
UnusedDocComment: UnusedDocComment,
+ UnexpectedCfgs: UnexpectedCfgs,
]
);
};
VariantSizeDifferences: VariantSizeDifferences,
BoxPointers: BoxPointers,
PathStatements: PathStatements,
+ LetUnderscore: LetUnderscore,
// Depends on referenced function signatures in expressions
UnusedResults: UnusedResults,
NonUpperCaseGlobals: NonUpperCaseGlobals,
REDUNDANT_SEMICOLONS
);
+ add_lint_group!("let_underscore", LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK);
+
add_lint_group!(
"rust_2018_idioms",
BARE_TRAIT_OBJECTS,
fn first_method_call<'tcx>(
expr: &'tcx Expr<'tcx>,
-) -> Option<(&'tcx PathSegment<'tcx>, &'tcx [Expr<'tcx>])> {
- if let ExprKind::MethodCall(path, args, _) = &expr.kind {
- if args.iter().any(|e| e.span.from_expansion()) { None } else { Some((path, *args)) }
+) -> Option<(&'tcx PathSegment<'tcx>, &'tcx Expr<'tcx>)> {
+ if let ExprKind::MethodCall(path, receiver, args, ..) = &expr.kind {
+ if args.iter().any(|e| e.span.from_expansion()) || receiver.span.from_expansion() {
+ None
+ } else {
+ Some((path, *receiver))
+ }
} else {
None
}
}
match first_method_call(expr) {
- Some((path, args)) if path.ident.name == sym::as_ptr => {
- let unwrap_arg = &args[0];
+ Some((path, unwrap_arg)) if path.ident.name == sym::as_ptr => {
let as_ptr_span = path.ident.span;
match first_method_call(unwrap_arg) {
- Some((path, args))
+ Some((path, receiver))
if path.ident.name == sym::unwrap || path.ident.name == sym::expect =>
{
- let source_arg = &args[0];
- lint_cstring_as_ptr(cx, as_ptr_span, source_arg, unwrap_arg);
+ lint_cstring_as_ptr(cx, as_ptr_span, receiver, unwrap_arg);
}
_ => return,
}
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// We only care about method calls.
- let ExprKind::MethodCall(call, elements, _) = &expr.kind else {
+ let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else {
return
};
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
) {
return;
}
- let receiver = &elements[0];
let receiver_ty = cx.typeck_results().expr_ty(receiver);
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
if receiver_ty != expr_ty {
use std::cmp;
use std::iter;
use std::ops::ControlFlow;
-use tracing::debug;
declare_lint! {
/// The `unused_comparisons` lint detects comparisons made useless by
sym::AtomicI64,
sym::AtomicI128,
];
- if let ExprKind::MethodCall(ref method_path, args, _) = &expr.kind
+ if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind
&& recognized_names.contains(&method_path.ident.name)
&& let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& let Some(impl_did) = cx.tcx.impl_of_method(m_def_id)
fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
&& let Some((ordering_arg, invalid_ordering)) = match method {
- sym::load => Some((&args[1], sym::Release)),
- sym::store => Some((&args[2], sym::Acquire)),
+ sym::load => Some((&args[0], sym::Release)),
+ sym::store => Some((&args[1], sym::Acquire)),
_ => None,
}
&& let Some(ordering) = Self::match_ordering(cx, ordering_arg)
else {return };
let fail_order_arg = match method {
- sym::fetch_update => &args[2],
- sym::compare_exchange | sym::compare_exchange_weak => &args[4],
+ sym::fetch_update => &args[1],
+ sym::compare_exchange | sym::compare_exchange_weak => &args[3],
_ => return,
};
avoid_or: bool,
avoid_mut: bool,
) {
- use ast::{BindingMode, Mutability, PatKind};
+ use ast::{BindingAnnotation, PatKind};
if let PatKind::Paren(inner) = &value.kind {
match inner.kind {
// Avoid `p0 | .. | pn` if we should.
PatKind::Or(..) if avoid_or => return,
// Avoid `mut x` and `mut x @ p` if we should:
- PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ..) if avoid_mut => return,
+ PatKind::Ident(BindingAnnotation::MUT, ..) if avoid_mut => {
+ return;
+ }
// Otherwise proceed with linting.
_ => {}
}
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
DUPLICATE_MACRO_ATTRIBUTES,
SUSPICIOUS_AUTO_TRAIT_IMPLS,
- UNEXPECTED_CFGS,
DEPRECATED_WHERE_CLAUSE_LOCATION,
TEST_UNSTABLE_LINT,
FFI_UNWIND_CALLS,
///
/// ### Example of drop reorder
///
- /// ```rust,compile_fail
+ /// ```rust,edition2018,compile_fail
/// #![deny(rust_2021_incompatible_closure_captures)]
/// # #![allow(unused)]
///
///
/// ### Example of auto-trait
///
- /// ```rust,compile_fail
+ /// ```rust,edition2018,compile_fail
/// #![deny(rust_2021_incompatible_closure_captures)]
/// use std::thread;
///
use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;
-use syn::{spanned::Spanned, Meta, MetaList, MetaNameValue, NestedMeta, Path};
+use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path};
use synstructure::{BindingInfo, Structure, VariantInfo};
/// Which kind of suggestion is being created?
Verbose,
}
+impl FromStr for SubdiagnosticSuggestionKind {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "" => Ok(SubdiagnosticSuggestionKind::Normal),
+ "_short" => Ok(SubdiagnosticSuggestionKind::Short),
+ "_hidden" => Ok(SubdiagnosticSuggestionKind::Hidden),
+ "_verbose" => Ok(SubdiagnosticSuggestionKind::Verbose),
+ _ => Err(()),
+ }
+ }
+}
+
+impl SubdiagnosticSuggestionKind {
+ pub fn to_suggestion_style(&self) -> TokenStream {
+ match self {
+ SubdiagnosticSuggestionKind::Normal => {
+ quote! { rustc_errors::SuggestionStyle::ShowCode }
+ }
+ SubdiagnosticSuggestionKind::Short => {
+ quote! { rustc_errors::SuggestionStyle::HideCodeInline }
+ }
+ SubdiagnosticSuggestionKind::Hidden => {
+ quote! { rustc_errors::SuggestionStyle::HideCodeAlways }
+ }
+ SubdiagnosticSuggestionKind::Verbose => {
+ quote! { rustc_errors::SuggestionStyle::ShowAlways }
+ }
+ }
+ }
+}
+
/// Which kind of subdiagnostic is being created from a variant?
-#[derive(Clone, Copy)]
+#[derive(Clone)]
enum SubdiagnosticKind {
/// `#[label(...)]`
Label,
/// `#[warning(...)]`
Warn,
/// `#[suggestion{,_short,_hidden,_verbose}]`
- Suggestion(SubdiagnosticSuggestionKind),
-}
-
-impl FromStr for SubdiagnosticKind {
- type Err = ();
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "label" => Ok(SubdiagnosticKind::Label),
- "note" => Ok(SubdiagnosticKind::Note),
- "help" => Ok(SubdiagnosticKind::Help),
- "warning" => Ok(SubdiagnosticKind::Warn),
- "suggestion" => Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal)),
- "suggestion_short" => {
- Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short))
- }
- "suggestion_hidden" => {
- Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden))
- }
- "suggestion_verbose" => {
- Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose))
- }
- _ => Err(()),
- }
- }
+ Suggestion { suggestion_kind: SubdiagnosticSuggestionKind, code: TokenStream },
+ /// `#[multipart_suggestion{,_short,_hidden,_verbose}]`
+ MultipartSuggestion { suggestion_kind: SubdiagnosticSuggestionKind },
}
impl quote::IdentFragment for SubdiagnosticKind {
SubdiagnosticKind::Note => write!(f, "note"),
SubdiagnosticKind::Help => write!(f, "help"),
SubdiagnosticKind::Warn => write!(f, "warn"),
- SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal) => {
- write!(f, "suggestion")
- }
- SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short) => {
- write!(f, "suggestion_short")
- }
- SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden) => {
- write!(f, "suggestion_hidden")
- }
- SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose) => {
- write!(f, "suggestion_verbose")
+ SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"),
+ SubdiagnosticKind::MultipartSuggestion { .. } => {
+ write!(f, "multipart_suggestion_with_style")
}
}
}
variant,
span,
fields: fields_map,
- kinds: Vec::new(),
- slugs: Vec::new(),
- code: None,
span_field: None,
applicability: None,
+ has_suggestion_parts: false,
};
builder.into_tokens().unwrap_or_else(|v| v.to_compile_error())
});
/// derive builder.
fields: HashMap<String, TokenStream>,
- /// Subdiagnostic kind of the type/variant.
- kinds: Vec<(SubdiagnosticKind, proc_macro::Span)>,
-
- /// Slugs of the subdiagnostic - corresponds to the Fluent identifier for the message - from the
- /// `#[kind(slug)]` attribute on the type or variant.
- slugs: Vec<(Path, proc_macro::Span)>,
- /// If a suggestion, the code to suggest as a replacement - from the `#[kind(code = "...")]`
- /// attribute on the type or variant.
- code: Option<(TokenStream, proc_macro::Span)>,
-
/// Identifier for the binding to the `#[primary_span]` field.
span_field: Option<(proc_macro2::Ident, proc_macro::Span)>,
/// If a suggestion, the identifier for the binding to the `#[applicability]` field or a
/// `rustc_errors::Applicability::*` variant directly.
applicability: Option<(TokenStream, proc_macro::Span)>,
+
+ /// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error
+ /// during finalization if still `false`.
+ has_suggestion_parts: bool,
}
impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> {
}
}
+/// Provides frequently-needed information about the diagnostic kinds being derived for this type.
+#[derive(Clone, Copy, Debug)]
+struct KindsStatistics {
+ has_multipart_suggestion: bool,
+ all_multipart_suggestions: bool,
+ has_normal_suggestion: bool,
+}
+
+impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
+ fn from_iter<T: IntoIterator<Item = &'a SubdiagnosticKind>>(kinds: T) -> Self {
+ let mut ret = Self {
+ has_multipart_suggestion: false,
+ all_multipart_suggestions: true,
+ has_normal_suggestion: false,
+ };
+ for kind in kinds {
+ if let SubdiagnosticKind::MultipartSuggestion { .. } = kind {
+ ret.has_multipart_suggestion = true;
+ } else {
+ ret.all_multipart_suggestions = false;
+ }
+
+ if let SubdiagnosticKind::Suggestion { .. } = kind {
+ ret.has_normal_suggestion = true;
+ }
+ }
+ ret
+ }
+}
+
impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
- fn identify_kind(&mut self) -> Result<(), DiagnosticDeriveError> {
- for (i, attr) in self.variant.ast().attrs.iter().enumerate() {
+ fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
+ let mut kind_slugs = vec![];
+
+ for attr in self.variant.ast().attrs {
let span = attr.span().unwrap();
let name = attr.path.segments.last().unwrap().ident.to_string();
let name = name.as_str();
let meta = attr.parse_meta()?;
- let kind = match meta {
- Meta::List(MetaList { ref nested, .. }) => {
- let mut nested_iter = nested.into_iter();
- if let Some(nested_attr) = nested_iter.next() {
- match nested_attr {
- NestedMeta::Meta(Meta::Path(path)) => {
- self.slugs.push((path.clone(), span));
- }
- NestedMeta::Meta(meta @ Meta::NameValue(_))
- if matches!(
- meta.path().segments.last().unwrap().ident.to_string().as_str(),
- "code" | "applicability"
- ) =>
- {
- // don't error for valid follow-up attributes
- }
- nested_attr => {
- throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
- diag.help(
- "first argument of the attribute should be the diagnostic \
- slug",
- )
- })
- }
- };
- }
+ let Meta::List(MetaList { ref nested, .. }) = meta else {
+ throw_invalid_attr!(attr, &meta);
+ };
- for nested_attr in nested_iter {
- let meta = match nested_attr {
- NestedMeta::Meta(ref meta) => meta,
- _ => throw_invalid_nested_attr!(attr, &nested_attr),
- };
-
- let span = meta.span().unwrap();
- let nested_name = meta.path().segments.last().unwrap().ident.to_string();
- let nested_name = nested_name.as_str();
-
- match meta {
- Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
- match nested_name {
- "code" => {
- let formatted_str = self.build_format(&s.value(), s.span());
- self.code.set_once((formatted_str, span));
- }
- "applicability" => {
- let value = match Applicability::from_str(&s.value()) {
- Ok(v) => v,
- Err(()) => {
- span_err(span, "invalid applicability").emit();
- Applicability::Unspecified
- }
- };
- self.applicability.set_once((quote! { #value }, span));
- }
- _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
- diag.help(
- "only `code` and `applicability` are valid nested \
- attributes",
- )
- }),
- }
- }
- _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
- if matches!(meta, Meta::Path(_)) {
- diag.help(
- "a diagnostic slug must be the first argument to the \
- attribute",
- )
- } else {
- diag
- }
- }),
- }
+ let mut kind = match name {
+ "label" => SubdiagnosticKind::Label,
+ "note" => SubdiagnosticKind::Note,
+ "help" => SubdiagnosticKind::Help,
+ "warning" => SubdiagnosticKind::Warn,
+ _ => {
+ if let Some(suggestion_kind) =
+ name.strip_prefix("suggestion").and_then(|s| s.parse().ok())
+ {
+ SubdiagnosticKind::Suggestion { suggestion_kind, code: TokenStream::new() }
+ } else if let Some(suggestion_kind) =
+ name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
+ {
+ SubdiagnosticKind::MultipartSuggestion { suggestion_kind }
+ } else {
+ throw_invalid_attr!(attr, &meta);
}
-
- let Ok(kind) = SubdiagnosticKind::from_str(name) else {
- throw_invalid_attr!(attr, &meta)
- };
-
- kind
}
- _ => throw_invalid_attr!(attr, &meta),
};
- if matches!(
- kind,
- SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note
- ) && self.code.is_some()
- {
- throw_span_err!(
- span,
- &format!("`code` is not a valid nested attribute of a `{}` attribute", name)
- );
+ let mut slug = None;
+ let mut code = None;
+
+ let mut nested_iter = nested.into_iter();
+ if let Some(nested_attr) = nested_iter.next() {
+ match nested_attr {
+ NestedMeta::Meta(Meta::Path(path)) => {
+ slug.set_once((path.clone(), span));
+ }
+ NestedMeta::Meta(meta @ Meta::NameValue(_))
+ if matches!(
+ meta.path().segments.last().unwrap().ident.to_string().as_str(),
+ "code" | "applicability"
+ ) =>
+ {
+ // Don't error for valid follow-up attributes.
+ }
+ nested_attr => {
+ throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+ diag.help(
+ "first argument of the attribute should be the diagnostic \
+ slug",
+ )
+ })
+ }
+ };
}
- if matches!(
- kind,
- SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note
- ) && self.applicability.is_some()
- {
- throw_span_err!(
- span,
- &format!(
- "`applicability` is not a valid nested attribute of a `{}` attribute",
- name
- )
- );
+ for nested_attr in nested_iter {
+ let meta = match nested_attr {
+ NestedMeta::Meta(ref meta) => meta,
+ _ => throw_invalid_nested_attr!(attr, &nested_attr),
+ };
+
+ let span = meta.span().unwrap();
+ let nested_name = meta.path().segments.last().unwrap().ident.to_string();
+ let nested_name = nested_name.as_str();
+
+ let value = match meta {
+ Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => value,
+ Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+ diag.help("a diagnostic slug must be the first argument to the attribute")
+ }),
+ _ => throw_invalid_nested_attr!(attr, &nested_attr),
+ };
+
+ match nested_name {
+ "code" => {
+ if matches!(kind, SubdiagnosticKind::Suggestion { .. }) {
+ let formatted_str = self.build_format(&value.value(), value.span());
+ code.set_once((formatted_str, span));
+ } else {
+ span_err(
+ span,
+ &format!(
+ "`code` is not a valid nested attribute of a `{}` attribute",
+ name
+ ),
+ )
+ .emit();
+ }
+ }
+ "applicability" => {
+ if matches!(
+ kind,
+ SubdiagnosticKind::Suggestion { .. }
+ | SubdiagnosticKind::MultipartSuggestion { .. }
+ ) {
+ let value =
+ Applicability::from_str(&value.value()).unwrap_or_else(|()| {
+ span_err(span, "invalid applicability").emit();
+ Applicability::Unspecified
+ });
+ self.applicability.set_once((quote! { #value }, span));
+ } else {
+ span_err(
+ span,
+ &format!(
+ "`applicability` is not a valid nested attribute of a `{}` attribute",
+ name
+ )
+ ).emit();
+ }
+ }
+ _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+ diag.help("only `code` and `applicability` are valid nested attributes")
+ }),
+ }
}
- if self.slugs.len() != i + 1 {
+ let Some((slug, _)) = slug else {
throw_span_err!(
span,
&format!(
name
)
);
+ };
+
+ match kind {
+ SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => {
+ let Some((code, _)) = code else {
+ throw_span_err!(span, "suggestion without `code = \"...\"`");
+ };
+ *code_field = code;
+ }
+ SubdiagnosticKind::Label
+ | SubdiagnosticKind::Note
+ | SubdiagnosticKind::Help
+ | SubdiagnosticKind::Warn
+ | SubdiagnosticKind::MultipartSuggestion { .. } => {}
}
- self.kinds.push((kind, span));
+ kind_slugs.push((kind, slug))
}
- Ok(())
+ Ok(kind_slugs)
}
- fn generate_field_code(
+ /// Generates the code for a field with no attributes.
+ fn generate_field_set_arg(&mut self, binding: &BindingInfo<'_>) -> TokenStream {
+ let ast = binding.ast();
+ assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
+
+ let diag = &self.diag;
+ let ident = ast.ident.as_ref().unwrap();
+ quote! {
+ #diag.set_arg(
+ stringify!(#ident),
+ #binding
+ );
+ }
+ }
+
+ /// Generates the necessary code for all attributes on a field.
+ fn generate_field_attr_code(
&mut self,
binding: &BindingInfo<'_>,
- have_suggestion: bool,
- ) -> Result<TokenStream, DiagnosticDeriveError> {
+ kind_stats: KindsStatistics,
+ ) -> TokenStream {
let ast = binding.ast();
+ assert!(ast.attrs.len() > 0, "field without attributes generating attr code");
+ // Abstract over `Vec<T>` and `Option<T>` fields using `FieldInnerTy`, which will
+ // apply the generated code on each element in the `Vec` or `Option`.
let inner_ty = FieldInnerTy::from_type(&ast.ty);
- let info = FieldInfo {
- binding: binding,
- ty: inner_ty.inner_type().unwrap_or(&ast.ty),
- span: &ast.span(),
- };
+ ast.attrs
+ .iter()
+ .map(|attr| {
+ let info = FieldInfo {
+ binding,
+ ty: inner_ty.inner_type().unwrap_or(&ast.ty),
+ span: &ast.span(),
+ };
- for attr in &ast.attrs {
- let name = attr.path.segments.last().unwrap().ident.to_string();
- let name = name.as_str();
- let span = attr.span().unwrap();
+ let generated = self
+ .generate_field_code_inner(kind_stats, attr, info)
+ .unwrap_or_else(|v| v.to_compile_error());
- let meta = attr.parse_meta()?;
- match meta {
- Meta::Path(_) => match name {
- "primary_span" => {
- report_error_if_not_applied_to_span(attr, &info)?;
- self.span_field.set_once((binding.binding.clone(), span));
- return Ok(quote! {});
- }
- "applicability" if have_suggestion => {
- report_error_if_not_applied_to_applicability(attr, &info)?;
- let binding = binding.binding.clone();
- self.applicability.set_once((quote! { #binding }, span));
- return Ok(quote! {});
- }
- "applicability" => {
- span_err(span, "`#[applicability]` is only valid on suggestions").emit();
- return Ok(quote! {});
- }
- "skip_arg" => {
- return Ok(quote! {});
- }
- _ => throw_invalid_attr!(attr, &meta, |diag| {
+ inner_ty.with(binding, generated)
+ })
+ .collect()
+ }
+
+ fn generate_field_code_inner(
+ &mut self,
+ kind_stats: KindsStatistics,
+ attr: &Attribute,
+ info: FieldInfo<'_>,
+ ) -> Result<TokenStream, DiagnosticDeriveError> {
+ let meta = attr.parse_meta()?;
+ match meta {
+ Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path),
+ Meta::List(list @ MetaList { .. }) => {
+ self.generate_field_code_inner_list(kind_stats, attr, info, list)
+ }
+ _ => throw_invalid_attr!(attr, &meta),
+ }
+ }
+
+ /// Generates the code for a `[Meta::Path]`-like attribute on a field (e.g. `#[primary_span]`).
+ fn generate_field_code_inner_path(
+ &mut self,
+ kind_stats: KindsStatistics,
+ attr: &Attribute,
+ info: FieldInfo<'_>,
+ path: Path,
+ ) -> Result<TokenStream, DiagnosticDeriveError> {
+ let span = attr.span().unwrap();
+ let ident = &path.segments.last().unwrap().ident;
+ let name = ident.to_string();
+ let name = name.as_str();
+
+ match name {
+ "skip_arg" => Ok(quote! {}),
+ "primary_span" => {
+ if kind_stats.has_multipart_suggestion {
+ throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
diag.help(
- "only `primary_span`, `applicability` and `skip_arg` are valid field \
- attributes",
+ "multipart suggestions use one or more `#[suggestion_part]`s rather \
+ than one `#[primary_span]`",
)
- }),
- },
- _ => throw_invalid_attr!(attr, &meta),
+ })
+ }
+
+ report_error_if_not_applied_to_span(attr, &info)?;
+
+ let binding = info.binding.binding.clone();
+ self.span_field.set_once((binding, span));
+
+ Ok(quote! {})
}
+ "suggestion_part" => {
+ self.has_suggestion_parts = true;
+
+ if kind_stats.has_multipart_suggestion {
+ span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
+ .emit();
+ Ok(quote! {})
+ } else {
+ throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
+ diag.help(
+ "`#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead",
+ )
+ });
+ }
+ }
+ "applicability" => {
+ if kind_stats.has_multipart_suggestion || kind_stats.has_normal_suggestion {
+ report_error_if_not_applied_to_applicability(attr, &info)?;
+
+ let binding = info.binding.binding.clone();
+ self.applicability.set_once((quote! { #binding }, span));
+ } else {
+ span_err(span, "`#[applicability]` is only valid on suggestions").emit();
+ }
+
+ Ok(quote! {})
+ }
+ _ => throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
+ let mut span_attrs = vec![];
+ if kind_stats.has_multipart_suggestion {
+ span_attrs.push("suggestion_part");
+ }
+ if !kind_stats.all_multipart_suggestions {
+ span_attrs.push("primary_span")
+ }
+ diag.help(format!(
+ "only `{}`, `applicability` and `skip_arg` are valid field attributes",
+ span_attrs.join(", ")
+ ))
+ }),
}
+ }
- let ident = ast.ident.as_ref().unwrap();
+ /// Generates the code for a `[Meta::List]`-like attribute on a field (e.g.
+ /// `#[suggestion_part(code = "...")]`).
+ fn generate_field_code_inner_list(
+ &mut self,
+ kind_stats: KindsStatistics,
+ attr: &Attribute,
+ info: FieldInfo<'_>,
+ list: MetaList,
+ ) -> Result<TokenStream, DiagnosticDeriveError> {
+ let span = attr.span().unwrap();
+ let ident = &list.path.segments.last().unwrap().ident;
+ let name = ident.to_string();
+ let name = name.as_str();
+
+ match name {
+ "suggestion_part" => {
+ if !kind_stats.has_multipart_suggestion {
+ throw_invalid_attr!(attr, &Meta::List(list), |diag| {
+ diag.help(
+ "`#[suggestion_part(...)]` is only valid in multipart suggestions",
+ )
+ })
+ }
- let diag = &self.diag;
- let generated = quote! {
- #diag.set_arg(
- stringify!(#ident),
- #binding
- );
- };
+ self.has_suggestion_parts = true;
+
+ report_error_if_not_applied_to_span(attr, &info)?;
+
+ let mut code = None;
+ for nested_attr in list.nested.iter() {
+ let NestedMeta::Meta(ref meta) = nested_attr else {
+ throw_invalid_nested_attr!(attr, &nested_attr);
+ };
+
+ let span = meta.span().unwrap();
+ let nested_name = meta.path().segments.last().unwrap().ident.to_string();
+ let nested_name = nested_name.as_str();
- Ok(inner_ty.with(binding, generated))
+ let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) = meta else {
+ throw_invalid_nested_attr!(attr, &nested_attr);
+ };
+
+ match nested_name {
+ "code" => {
+ let formatted_str = self.build_format(&value.value(), value.span());
+ code.set_once((formatted_str, span));
+ }
+ _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+ diag.help("`code` is the only valid nested attribute")
+ }),
+ }
+ }
+
+ let Some((code, _)) = code else {
+ span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
+ .emit();
+ return Ok(quote! {});
+ };
+ let binding = info.binding;
+
+ Ok(quote! { suggestions.push((#binding, #code)); })
+ }
+ _ => throw_invalid_attr!(attr, &Meta::List(list), |diag| {
+ let mut span_attrs = vec![];
+ if kind_stats.has_multipart_suggestion {
+ span_attrs.push("suggestion_part");
+ }
+ if !kind_stats.all_multipart_suggestions {
+ span_attrs.push("primary_span")
+ }
+ diag.help(format!(
+ "only `{}`, `applicability` and `skip_arg` are valid field attributes",
+ span_attrs.join(", ")
+ ))
+ }),
+ }
}
- fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
- self.identify_kind()?;
- if self.kinds.is_empty() {
+ pub fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
+ let kind_slugs = self.identify_kind()?;
+ if kind_slugs.is_empty() {
throw_span_err!(
self.variant.ast().ident.span().unwrap(),
"subdiagnostic kind not specified"
);
};
- let have_suggestion =
- self.kinds.iter().any(|(k, _)| matches!(k, SubdiagnosticKind::Suggestion(_)));
- let mut args = TokenStream::new();
- for binding in self.variant.bindings() {
- let arg = self
- .generate_field_code(binding, have_suggestion)
- .unwrap_or_else(|v| v.to_compile_error());
- args.extend(arg);
- }
- let mut tokens = TokenStream::new();
- for ((kind, _), (slug, _)) in self.kinds.iter().zip(&self.slugs) {
- let code = match self.code.as_ref() {
- Some((code, _)) => Some(quote! { #code }),
- None if have_suggestion => {
- span_err(self.span, "suggestion without `code = \"...\"`").emit();
- Some(quote! { /* macro error */ "..." })
- }
- None => None,
- };
- let span_field = self.span_field.as_ref().map(|(span, _)| span);
- let applicability = match self.applicability.clone() {
- Some((applicability, _)) => Some(applicability),
- None if have_suggestion => {
- span_err(self.span, "suggestion without `applicability`").emit();
- Some(quote! { rustc_errors::Applicability::Unspecified })
- }
- None => None,
- };
+ let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect();
+
+ let init = if kind_stats.has_multipart_suggestion {
+ quote! { let mut suggestions = Vec::new(); }
+ } else {
+ quote! {}
+ };
+
+ let attr_args: TokenStream = self
+ .variant
+ .bindings()
+ .iter()
+ .filter(|binding| !binding.ast().attrs.is_empty())
+ .map(|binding| self.generate_field_attr_code(binding, kind_stats))
+ .collect();
+
+ let span_field = self.span_field.as_ref().map(|(span, _)| span);
+ let applicability = self.applicability.take().map_or_else(
+ || quote! { rustc_errors::Applicability::Unspecified },
+ |(applicability, _)| applicability,
+ );
- let diag = &self.diag;
+ let diag = &self.diag;
+ let mut calls = TokenStream::new();
+ for (kind, slug) in kind_slugs {
let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
let message = quote! { rustc_errors::fluent::#slug };
- let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) {
- if let Some(span) = span_field {
- quote! { #diag.#name(#span, #message, #code, #applicability); }
- } else {
- span_err(self.span, "suggestion without `#[primary_span]` field").emit();
- quote! { unreachable!(); }
+ let call = match kind {
+ SubdiagnosticKind::Suggestion { suggestion_kind, code } => {
+ if let Some(span) = span_field {
+ let style = suggestion_kind.to_suggestion_style();
+
+ quote! { #diag.#name(#span, #message, #code, #applicability, #style); }
+ } else {
+ span_err(self.span, "suggestion without `#[primary_span]` field").emit();
+ quote! { unreachable!(); }
+ }
}
- } else if matches!(kind, SubdiagnosticKind::Label) {
- if let Some(span) = span_field {
- quote! { #diag.#name(#span, #message); }
- } else {
- span_err(self.span, "label without `#[primary_span]` field").emit();
- quote! { unreachable!(); }
+ SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => {
+ if !self.has_suggestion_parts {
+ span_err(
+ self.span,
+ "multipart suggestion without any `#[suggestion_part(...)]` fields",
+ )
+ .emit();
+ }
+
+ let style = suggestion_kind.to_suggestion_style();
+
+ quote! { #diag.#name(#message, suggestions, #applicability, #style); }
}
- } else {
- if let Some(span) = span_field {
- quote! { #diag.#name(#span, #message); }
- } else {
- quote! { #diag.#name(#message); }
+ SubdiagnosticKind::Label => {
+ if let Some(span) = span_field {
+ quote! { #diag.#name(#span, #message); }
+ } else {
+ span_err(self.span, "label without `#[primary_span]` field").emit();
+ quote! { unreachable!(); }
+ }
+ }
+ _ => {
+ if let Some(span) = span_field {
+ quote! { #diag.#name(#span, #message); }
+ } else {
+ quote! { #diag.#name(#message); }
+ }
}
};
- tokens.extend(quote! {
- #call
- #args
- });
+ calls.extend(call);
}
- Ok(tokens)
+ let plain_args: TokenStream = self
+ .variant
+ .bindings()
+ .iter()
+ .filter(|binding| binding.ast().attrs.is_empty())
+ .map(|binding| self.generate_field_set_arg(binding))
+ .collect();
+
+ Ok(quote! {
+ #init
+ #attr_args
+ #calls
+ #plain_args
+ })
}
}
//! Validates all used crates and extern libraries and loads their metadata
+use crate::errors::{
+ ConflictingGlobalAlloc, CrateNotPanicRuntime, GlobalAllocRequired, NoMultipleGlobalAlloc,
+ NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore,
+};
use crate::locator::{CrateError, CrateLocator, CratePaths};
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
use std::ops::Fn;
use std::path::Path;
use std::{cmp, env};
-use tracing::{debug, info};
#[derive(Clone)]
pub struct CStore {
fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Option<CrateNum> {
for (cnum, data) in self.cstore.iter_crate_data() {
if data.name() != name {
- tracing::trace!("{} did not match {}", data.name(), name);
+ trace!("{} did not match {}", data.name(), name);
continue;
}
// Sanity check the loaded crate to ensure it is indeed a panic runtime
// and the panic strategy is indeed what we thought it was.
if !data.is_panic_runtime() {
- self.sess.err(&format!("the crate `{}` is not a panic runtime", name));
+ self.sess.emit_err(CrateNotPanicRuntime { crate_name: name });
}
if data.required_panic_strategy() != Some(desired_strategy) {
- self.sess.err(&format!(
- "the crate `{}` does not have the panic \
- strategy `{}`",
- name,
- desired_strategy.desc()
- ));
+ self.sess.emit_err(NoPanicStrategy { crate_name: name, strategy: desired_strategy });
}
self.cstore.injected_panic_runtime = Some(cnum);
let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) {
- self.sess.err(
- "`profiler_builtins` crate (required by compiler options) \
- is not compatible with crate attribute `#![no_core]`",
- );
+ self.sess.emit_err(ProfilerBuiltinsNeedsCore);
}
let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; };
// Sanity check the loaded crate to ensure it is indeed a profiler runtime
if !data.is_profiler_runtime() {
- self.sess.err(&format!("the crate `{}` is not a profiler runtime", name));
+ self.sess.emit_err(NotProfilerRuntime { crate_name: name });
}
}
fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) {
[span1, span2, ..] => {
- self.sess
- .struct_span_err(*span2, "cannot define multiple global allocators")
- .span_label(*span2, "cannot define a new global allocator")
- .span_label(*span1, "previous global allocator defined here")
- .emit();
+ self.sess.emit_err(NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
true
}
spans => !spans.is_empty(),
if data.has_global_allocator() {
match global_allocator {
Some(other_crate) => {
- self.sess.err(&format!(
- "the `#[global_allocator]` in {} conflicts with global allocator in: {}",
- other_crate,
- data.name()
- ));
+ self.sess.emit_err(ConflictingGlobalAlloc {
+ crate_name: data.name(),
+ other_crate_name: other_crate,
+ });
}
None => global_allocator = Some(data.name()),
}
if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
&& !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
{
- self.sess.err(
- "no global memory allocator found but one is required; link to std or add \
- `#[global_allocator]` to a static item that implements the GlobalAlloc trait",
- );
+ self.sess.emit_err(GlobalAllocRequired);
}
self.cstore.allocator_kind = Some(AllocatorKind::Default);
}
for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) {
let data = self.cstore.get_crate_data(dep);
if needs_dep(&data) {
- self.sess.err(&format!(
- "the crate `{}` cannot depend \
- on a crate that needs {}, but \
- it depends on `{}`",
- self.cstore.get_crate_data(krate).name(),
- what,
- data.name()
- ));
+ self.sess.emit_err(NoTransitiveNeedsDep {
+ crate_name: self.cstore.get_crate_data(krate).name(),
+ needs_crate_name: what,
+ deps_crate_name: data.name(),
+ });
}
}
//! than finding a number of solutions (there are normally quite a few).
use crate::creader::CStore;
+use crate::errors::{
+ BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
+ RequiredPanicStrategy, RlibRequired, TwoPanicRuntimes,
+};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::CrateNum;
if src.rlib.is_some() {
continue;
}
- sess.err(&format!(
- "crate `{}` required to be available in rlib format, \
- but was not found in this form",
- tcx.crate_name(cnum)
- ));
+ sess.emit_err(RlibRequired { crate_name: tcx.crate_name(cnum) });
}
return Vec::new();
}
let name = tcx.crate_name(cnum);
let src = tcx.used_crate_source(cnum);
if src.dylib.is_some() {
- tracing::info!("adding dylib: {}", name);
+ info!("adding dylib: {}", name);
add_library(tcx, cnum, RequireDynamic, &mut formats);
let deps = tcx.dylib_dependency_formats(cnum);
for &(depnum, style) in deps.iter() {
- tracing::info!("adding {:?}: {}", style, tcx.crate_name(depnum));
+ info!("adding {:?}: {}", style, tcx.crate_name(depnum));
add_library(tcx, depnum, style, &mut formats);
}
}
&& tcx.dep_kind(cnum) == CrateDepKind::Explicit
{
assert!(src.rlib.is_some() || src.rmeta.is_some());
- tracing::info!("adding staticlib: {}", tcx.crate_name(cnum));
+ info!("adding staticlib: {}", tcx.crate_name(cnum));
add_library(tcx, cnum, RequireStatic, &mut formats);
ret[cnum.as_usize() - 1] = Linkage::Static;
}
Linkage::Static => "rlib",
_ => "dylib",
};
- sess.err(&format!(
- "crate `{}` required to be available in {} format, \
- but was not found in this form",
- tcx.crate_name(cnum),
- kind
- ));
+ sess.emit_err(LibRequired { crate_name: tcx.crate_name(cnum), kind: kind });
}
}
}
// This error is probably a little obscure, but I imagine that it
// can be refined over time.
if link2 != link || link == RequireStatic {
- tcx.sess
- .struct_err(&format!(
- "cannot satisfy dependencies so `{}` only \
- shows up once",
- tcx.crate_name(cnum)
- ))
- .help(
- "having upstream crates all available in one format \
- will likely make this go away",
- )
- .emit();
+ tcx.sess.emit_err(CrateDepMultiple { crate_name: tcx.crate_name(cnum) });
}
}
None => {
if let Some((prev, _)) = panic_runtime {
let prev_name = tcx.crate_name(prev);
let cur_name = tcx.crate_name(cnum);
- sess.err(&format!(
- "cannot link together two \
- panic runtimes: {} and {}",
- prev_name, cur_name
- ));
+ sess.emit_err(TwoPanicRuntimes { prev_name, cur_name });
}
panic_runtime = Some((
cnum,
// First up, validate that our selected panic runtime is indeed exactly
// our same strategy.
if found_strategy != desired_strategy {
- sess.err(&format!(
- "the linked panic runtime `{}` is \
- not compiled with this crate's \
- panic strategy `{}`",
- tcx.crate_name(runtime_cnum),
- desired_strategy.desc()
- ));
+ sess.emit_err(BadPanicStrategy {
+ runtime: tcx.crate_name(runtime_cnum),
+ strategy: desired_strategy,
+ });
}
// Next up, verify that all other crates are compatible with this panic
}
if let Some(found_strategy) = tcx.required_panic_strategy(cnum) && desired_strategy != found_strategy {
- sess.err(&format!(
- "the crate `{}` requires \
- panic strategy `{}` which is \
- incompatible with this crate's \
- strategy of `{}`",
- tcx.crate_name(cnum),
- found_strategy.desc(),
- desired_strategy.desc()
- ));
+ sess.emit_err(RequiredPanicStrategy {
+ crate_name: tcx.crate_name(cnum),
+ found_strategy,
+ desired_strategy});
}
let found_drop_strategy = tcx.panic_in_drop_strategy(cnum);
if tcx.sess.opts.unstable_opts.panic_in_drop != found_drop_strategy {
- sess.err(&format!(
- "the crate `{}` is compiled with the \
- panic-in-drop strategy `{}` which is \
- incompatible with this crate's \
- strategy of `{}`",
- tcx.crate_name(cnum),
- found_drop_strategy.desc(),
- tcx.sess.opts.unstable_opts.panic_in_drop.desc()
- ));
+ sess.emit_err(IncompatiblePanicInDropStrategy {
+ crate_name: tcx.crate_name(cnum),
+ found_strategy: found_drop_strategy,
+ desired_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
+ });
}
}
}
--- /dev/null
+use std::{
+ io::Error,
+ path::{Path, PathBuf},
+};
+
+use rustc_errors::{error_code, ErrorGuaranteed};
+use rustc_macros::SessionDiagnostic;
+use rustc_session::{config, SessionDiagnostic};
+use rustc_span::{sym, Span, Symbol};
+use rustc_target::spec::{PanicStrategy, TargetTriple};
+
+use crate::locator::CrateFlavor;
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::rlib_required)]
+pub struct RlibRequired {
+ pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::lib_required)]
+pub struct LibRequired<'a> {
+ pub crate_name: Symbol,
+ pub kind: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::crate_dep_multiple)]
+#[help]
+pub struct CrateDepMultiple {
+ pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::two_panic_runtimes)]
+pub struct TwoPanicRuntimes {
+ pub prev_name: Symbol,
+ pub cur_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::bad_panic_strategy)]
+pub struct BadPanicStrategy {
+ pub runtime: Symbol,
+ pub strategy: PanicStrategy,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::required_panic_strategy)]
+pub struct RequiredPanicStrategy {
+ pub crate_name: Symbol,
+ pub found_strategy: PanicStrategy,
+ pub desired_strategy: PanicStrategy,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::incompatible_panic_in_drop_strategy)]
+pub struct IncompatiblePanicInDropStrategy {
+ pub crate_name: Symbol,
+ pub found_strategy: PanicStrategy,
+ pub desired_strategy: PanicStrategy,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_names_in_link)]
+pub struct MultipleNamesInLink {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_kinds_in_link)]
+pub struct MultipleKindsInLink {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_name_form)]
+pub struct LinkNameForm {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_kind_form)]
+pub struct LinkKindForm {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_modifiers_form)]
+pub struct LinkModifiersForm {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_cfg_form)]
+pub struct LinkCfgForm {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::wasm_import_form)]
+pub struct WasmImportForm {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::empty_link_name, code = "E0454")]
+pub struct EmptyLinkName {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_framework_apple, code = "E0455")]
+pub struct LinkFrameworkApple {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::framework_only_windows, code = "E0455")]
+pub struct FrameworkOnlyWindows {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unknown_link_kind, code = "E0458")]
+pub struct UnknownLinkKind<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub kind: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_link_modifiers)]
+pub struct MultipleLinkModifiers {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_cfgs)]
+pub struct MultipleCfgs {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_cfg_single_predicate)]
+pub struct LinkCfgSinglePredicate {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_wasm_import)]
+pub struct MultipleWasmImport {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unexpected_link_arg)]
+pub struct UnexpectedLinkArg {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::invalid_link_modifier)]
+pub struct InvalidLinkModifier {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_modifiers)]
+pub struct MultipleModifiers<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub modifier: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::bundle_needs_static)]
+pub struct BundleNeedsStatic {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::whole_archive_needs_static)]
+pub struct WholeArchiveNeedsStatic {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::as_needed_compatibility)]
+pub struct AsNeededCompatibility {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unknown_link_modifier)]
+pub struct UnknownLinkModifier<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub modifier: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::incompatible_wasm_link)]
+pub struct IncompatibleWasmLink {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_requires_name, code = "E0459")]
+pub struct LinkRequiresName {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::raw_dylib_no_nul)]
+pub struct RawDylibNoNul {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_ordinal_raw_dylib)]
+pub struct LinkOrdinalRawDylib {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::lib_framework_apple)]
+pub struct LibFrameworkApple;
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::empty_renaming_target)]
+pub struct EmptyRenamingTarget<'a> {
+ pub lib_name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::renaming_no_link)]
+pub struct RenamingNoLink<'a> {
+ pub lib_name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_renamings)]
+pub struct MultipleRenamings<'a> {
+ pub lib_name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_link_mod_override)]
+pub struct NoLinkModOverride {
+ #[primary_span]
+ pub span: Option<Span>,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unsupported_abi_i686)]
+pub struct UnsupportedAbiI686 {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unsupported_abi)]
+pub struct UnsupportedAbi {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::fail_create_file_encoder)]
+pub struct FailCreateFileEncoder {
+ pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::fail_seek_file)]
+pub struct FailSeekFile {
+ pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::fail_write_file)]
+pub struct FailWriteFile {
+ pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::crate_not_panic_runtime)]
+pub struct CrateNotPanicRuntime {
+ pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_panic_strategy)]
+pub struct NoPanicStrategy {
+ pub crate_name: Symbol,
+ pub strategy: PanicStrategy,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::profiler_builtins_needs_core)]
+pub struct ProfilerBuiltinsNeedsCore;
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::not_profiler_runtime)]
+pub struct NotProfilerRuntime {
+ pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_multiple_global_alloc)]
+pub struct NoMultipleGlobalAlloc {
+ #[primary_span]
+ #[label]
+ pub span2: Span,
+ #[label(metadata::prev_global_alloc)]
+ pub span1: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::conflicting_global_alloc)]
+pub struct ConflictingGlobalAlloc {
+ pub crate_name: Symbol,
+ pub other_crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::global_alloc_required)]
+pub struct GlobalAllocRequired;
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_transitive_needs_dep)]
+pub struct NoTransitiveNeedsDep<'a> {
+ pub crate_name: Symbol,
+ pub needs_crate_name: &'a str,
+ pub deps_crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::failed_write_error)]
+pub struct FailedWriteError {
+ pub filename: PathBuf,
+ pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::failed_create_tempdir)]
+pub struct FailedCreateTempdir {
+ pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::failed_create_file)]
+pub struct FailedCreateFile<'a> {
+ pub filename: &'a Path,
+ pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::failed_create_encoded_metadata)]
+pub struct FailedCreateEncodedMetadata {
+ pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::non_ascii_name)]
+pub struct NonAsciiName {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::extern_location_not_exist)]
+pub struct ExternLocationNotExist<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: Symbol,
+ pub location: &'a Path,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::extern_location_not_file)]
+pub struct ExternLocationNotFile<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: Symbol,
+ pub location: &'a Path,
+}
+
+pub(crate) struct MultipleCandidates {
+ pub span: Span,
+ pub flavor: CrateFlavor,
+ pub crate_name: Symbol,
+ pub candidates: Vec<PathBuf>,
+}
+
+impl SessionDiagnostic<'_> for MultipleCandidates {
+ fn into_diagnostic(
+ self,
+ sess: &'_ rustc_session::parse::ParseSess,
+ ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag = sess.struct_err(rustc_errors::fluent::metadata::multiple_candidates);
+ diag.set_arg("crate_name", self.crate_name);
+ diag.set_arg("flavor", self.flavor);
+ diag.code(error_code!(E0465));
+ diag.set_span(self.span);
+ for (i, candidate) in self.candidates.iter().enumerate() {
+ diag.span_note(self.span, &format!("candidate #{}: {}", i + 1, candidate.display()));
+ }
+ diag
+ }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_matching_crates, code = "E0464")]
+#[note]
+pub struct MultipleMatchingCrates {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: Symbol,
+ pub candidates: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::symbol_conflicts_current, code = "E0519")]
+pub struct SymbolConflictsCurrent {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::symbol_conflicts_others, code = "E0523")]
+pub struct SymbolConflictsOthers {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::stable_crate_id_collision)]
+pub struct StableCrateIdCollision {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name0: Symbol,
+ pub crate_name1: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::dl_error)]
+pub struct DlError {
+ #[primary_span]
+ pub span: Span,
+ pub err: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::newer_crate_version, code = "E0460")]
+#[note]
+#[note(metadata::found_crate_versions)]
+pub struct NewerCrateVersion {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: Symbol,
+ pub add_info: String,
+ pub found_crates: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_crate_with_triple, code = "E0461")]
+#[note(metadata::found_crate_versions)]
+pub struct NoCrateWithTriple<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: Symbol,
+ pub locator_triple: &'a str,
+ pub add_info: String,
+ pub found_crates: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::found_staticlib, code = "E0462")]
+#[note(metadata::found_crate_versions)]
+#[help]
+pub struct FoundStaticlib {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: Symbol,
+ pub add_info: String,
+ pub found_crates: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::incompatible_rustc, code = "E0514")]
+#[note(metadata::found_crate_versions)]
+#[help]
+pub struct IncompatibleRustc {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: Symbol,
+ pub add_info: String,
+ pub found_crates: String,
+ pub rustc_version: String,
+}
+
+pub struct InvalidMetadataFiles {
+ pub span: Span,
+ pub crate_name: Symbol,
+ pub add_info: String,
+ pub crate_rejections: Vec<String>,
+}
+
+impl SessionDiagnostic<'_> for InvalidMetadataFiles {
+ fn into_diagnostic(
+ self,
+ sess: &'_ rustc_session::parse::ParseSess,
+ ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag = sess.struct_err(rustc_errors::fluent::metadata::invalid_meta_files);
+ diag.set_arg("crate_name", self.crate_name);
+ diag.set_arg("add_info", self.add_info);
+ diag.code(error_code!(E0786));
+ diag.set_span(self.span);
+ for crate_rejection in self.crate_rejections {
+ diag.note(crate_rejection);
+ }
+ diag
+ }
+}
+
+pub struct CannotFindCrate {
+ pub span: Span,
+ pub crate_name: Symbol,
+ pub add_info: String,
+ pub missing_core: bool,
+ pub current_crate: String,
+ pub is_nightly_build: bool,
+ pub profiler_runtime: Symbol,
+ pub locator_triple: TargetTriple,
+}
+
+impl SessionDiagnostic<'_> for CannotFindCrate {
+ fn into_diagnostic(
+ self,
+ sess: &'_ rustc_session::parse::ParseSess,
+ ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag = sess.struct_err(rustc_errors::fluent::metadata::cannot_find_crate);
+ diag.set_arg("crate_name", self.crate_name);
+ diag.set_arg("add_info", self.add_info);
+ diag.set_arg("locator_triple", self.locator_triple.triple());
+ diag.code(error_code!(E0463));
+ diag.set_span(self.span);
+ if (self.crate_name == sym::std || self.crate_name == sym::core)
+ && self.locator_triple != TargetTriple::from_triple(config::host_triple())
+ {
+ if self.missing_core {
+ diag.note(rustc_errors::fluent::metadata::target_not_installed);
+ } else {
+ diag.note(rustc_errors::fluent::metadata::target_no_std_support);
+ }
+ // NOTE: this suggests using rustup, even though the user may not have it installed.
+ // That's because they could choose to install it; or this may give them a hint which
+ // target they need to install from their distro.
+ if self.missing_core {
+ diag.help(rustc_errors::fluent::metadata::consider_downloading_target);
+ }
+ // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway.
+ // NOTE: this is a dummy span if `extern crate std` was injected by the compiler.
+ // If it's not a dummy, that means someone added `extern crate std` explicitly and
+ // `#![no_std]` won't help.
+ if !self.missing_core && self.span.is_dummy() {
+ diag.note(rustc_errors::fluent::metadata::std_required);
+ }
+ if self.is_nightly_build {
+ diag.help(rustc_errors::fluent::metadata::consider_building_std);
+ }
+ } else if self.crate_name == self.profiler_runtime {
+ diag.note(rustc_errors::fluent::metadata::compiler_missing_profiler);
+ } else if self.crate_name.as_str().starts_with("rustc_") {
+ diag.help(rustc_errors::fluent::metadata::install_missing_components);
+ }
+ diag.span_label(self.span, rustc_errors::fluent::metadata::cant_find_crate);
+ diag
+ }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_dylib_plugin, code = "E0457")]
+pub struct NoDylibPlugin {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::crate_location_unknown_type)]
+pub struct CrateLocationUnknownType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub path: &'a Path,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::lib_filename_form)]
+pub struct LibFilenameForm<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub dll_prefix: &'a str,
+ pub dll_suffix: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_import_name_type)]
+pub struct MultipleImportNameType {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::import_name_type_form)]
+pub struct ImportNameTypeForm {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::import_name_type_x86)]
+pub struct ImportNameTypeX86 {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unknown_import_name_type)]
+pub struct UnknownImportNameType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub import_name_type: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::import_name_type_raw)]
+pub struct ImportNameTypeRaw {
+ #[primary_span]
+ pub span: Span,
+}
+use crate::errors::{
+ FailedCreateEncodedMetadata, FailedCreateFile, FailedCreateTempdir, FailedWriteError,
+};
use crate::{encode_metadata, EncodedMetadata};
use rustc_data_structures::temp_dir::MaybeTempDir;
let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
let result = fs::write(&out_filename, metadata);
- if let Err(e) = result {
- sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
+ if let Err(err) = result {
+ sess.emit_fatal(FailedWriteError { filename: out_filename, err });
}
out_filename
let metadata_tmpdir = TempFileBuilder::new()
.prefix("rmeta")
.tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new("")))
- .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
+ .unwrap_or_else(|err| tcx.sess.emit_fatal(FailedCreateTempdir { err }));
let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
let metadata_filename = metadata_tmpdir.as_ref().join(METADATA_FILENAME);
// This simplifies the creation of the output `out_filename` when requested.
match metadata_kind {
MetadataKind::None => {
- std::fs::File::create(&metadata_filename).unwrap_or_else(|e| {
- tcx.sess.fatal(&format!(
- "failed to create the file {}: {}",
- metadata_filename.display(),
- e
- ))
+ std::fs::File::create(&metadata_filename).unwrap_or_else(|err| {
+ tcx.sess.emit_fatal(FailedCreateFile { filename: &metadata_filename, err });
});
}
MetadataKind::Uncompressed | MetadataKind::Compressed => {
// this file always exists.
let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
let (metadata_filename, metadata_tmpdir) = if need_metadata_file {
- if let Err(e) = non_durable_rename(&metadata_filename, &out_filename) {
- tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
+ if let Err(err) = non_durable_rename(&metadata_filename, &out_filename) {
+ tcx.sess.emit_fatal(FailedWriteError { filename: out_filename, err });
}
if tcx.sess.opts.json_artifact_notifications {
tcx.sess
// Load metadata back to memory: codegen may need to include it in object files.
let metadata =
- EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|e| {
- tcx.sess.fatal(&format!("failed to create encoded metadata from file: {}", e))
+ EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|err| {
+ tcx.sess.emit_fatal(FailedCreateEncodedMetadata { err });
});
let need_metadata_module = metadata_kind == MetadataKind::Compressed;
#![feature(never_type)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
extern crate proc_macro;
#[macro_use]
extern crate rustc_data_structures;
+#[macro_use]
+extern crate tracing;
+
pub use rmeta::{provide, provide_extern};
mod dependency_format;
mod rmeta;
pub mod creader;
+pub mod errors;
pub mod fs;
pub mod locator;
//! metadata::locator or metadata::creader for all the juicy details!
use crate::creader::Library;
+use crate::errors::{
+ CannotFindCrate, CrateLocationUnknownType, DlError, ExternLocationNotExist,
+ ExternLocationNotFile, FoundStaticlib, IncompatibleRustc, InvalidMetadataFiles,
+ LibFilenameForm, MultipleCandidates, MultipleMatchingCrates, NewerCrateVersion,
+ NoCrateWithTriple, NoDylibPlugin, NonAsciiName, StableCrateIdCollision, SymbolConflictsCurrent,
+ SymbolConflictsOthers,
+};
use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::MetadataRef;
-use rustc_errors::{struct_span_err, FatalError};
+use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg};
use rustc_session::config::{self, CrateType};
use rustc_session::cstore::{CrateSource, MetadataLoader};
use rustc_session::filesearch::FileSearch;
use rustc_session::search_paths::PathKind;
use rustc_session::utils::CanonicalizedPath;
use rustc_session::Session;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::Symbol;
use rustc_span::Span;
use rustc_target::spec::{Target, TargetTriple};
use snap::read::FrameDecoder;
+use std::borrow::Cow;
use std::fmt::Write as _;
use std::io::{Read, Result as IoResult, Write};
use std::path::{Path, PathBuf};
use std::{cmp, fmt, fs};
-use tracing::{debug, info};
#[derive(Clone)]
pub(crate) struct CrateLocator<'a> {
}
}
+impl IntoDiagnosticArg for CrateFlavor {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ match self {
+ CrateFlavor::Rlib => DiagnosticArgValue::Str(Cow::Borrowed("rlib")),
+ CrateFlavor::Rmeta => DiagnosticArgValue::Str(Cow::Borrowed("rmeta")),
+ CrateFlavor::Dylib => DiagnosticArgValue::Str(Cow::Borrowed("dylib")),
+ }
+ }
+}
+
impl<'a> CrateLocator<'a> {
pub(crate) fn new(
sess: &'a Session,
impl CrateError {
pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
- let mut diag = match self {
- CrateError::NonAsciiName(crate_name) => sess.struct_span_err(
- span,
- &format!("cannot load a crate with a non-ascii name `{}`", crate_name),
- ),
- CrateError::ExternLocationNotExist(crate_name, loc) => sess.struct_span_err(
- span,
- &format!("extern location for {} does not exist: {}", crate_name, loc.display()),
- ),
- CrateError::ExternLocationNotFile(crate_name, loc) => sess.struct_span_err(
- span,
- &format!("extern location for {} is not a file: {}", crate_name, loc.display()),
- ),
+ match self {
+ CrateError::NonAsciiName(crate_name) => {
+ sess.emit_err(NonAsciiName { span, crate_name });
+ }
+ CrateError::ExternLocationNotExist(crate_name, loc) => {
+ sess.emit_err(ExternLocationNotExist { span, crate_name, location: &loc });
+ }
+ CrateError::ExternLocationNotFile(crate_name, loc) => {
+ sess.emit_err(ExternLocationNotFile { span, crate_name, location: &loc });
+ }
CrateError::MultipleCandidates(crate_name, flavor, candidates) => {
- let mut err = struct_span_err!(
- sess,
- span,
- E0465,
- "multiple {} candidates for `{}` found",
- flavor,
- crate_name,
- );
- for (i, candidate) in candidates.iter().enumerate() {
- err.span_note(span, &format!("candidate #{}: {}", i + 1, candidate.display()));
- }
- err
+ sess.emit_err(MultipleCandidates { span, flavor: flavor, crate_name, candidates });
}
CrateError::MultipleMatchingCrates(crate_name, libraries) => {
- let mut err = struct_span_err!(
- sess,
- span,
- E0464,
- "multiple matching crates for `{}`",
- crate_name
- );
let mut libraries: Vec<_> = libraries.into_values().collect();
// Make ordering of candidates deterministic.
// This has to `clone()` to work around lifetime restrictions with `sort_by_key()`.
s
})
.collect::<String>();
- err.note(&format!("candidates:{}", candidates));
- err
+ sess.emit_err(MultipleMatchingCrates { span, crate_name, candidates });
+ }
+ CrateError::SymbolConflictsCurrent(root_name) => {
+ sess.emit_err(SymbolConflictsCurrent { span, crate_name: root_name });
+ }
+ CrateError::SymbolConflictsOthers(root_name) => {
+ sess.emit_err(SymbolConflictsOthers { span, crate_name: root_name });
}
- CrateError::SymbolConflictsCurrent(root_name) => struct_span_err!(
- sess,
- span,
- E0519,
- "the current crate is indistinguishable from one of its dependencies: it has the \
- same crate-name `{}` and was compiled with the same `-C metadata` arguments. \
- This will result in symbol conflicts between the two.",
- root_name,
- ),
- CrateError::SymbolConflictsOthers(root_name) => struct_span_err!(
- sess,
- span,
- E0523,
- "found two different crates with name `{}` that are not distinguished by differing \
- `-C metadata`. This will result in symbol conflicts between the two.",
- root_name,
- ),
CrateError::StableCrateIdCollision(crate_name0, crate_name1) => {
- let msg = format!(
- "found crates (`{}` and `{}`) with colliding StableCrateId values.",
- crate_name0, crate_name1
- );
- sess.struct_span_err(span, &msg)
+ sess.emit_err(StableCrateIdCollision {
+ span,
+ crate_name0: crate_name0,
+ crate_name1: crate_name1,
+ });
+ }
+ CrateError::DlOpen(s) | CrateError::DlSym(s) => {
+ sess.emit_err(DlError { span, err: s });
}
- CrateError::DlOpen(s) | CrateError::DlSym(s) => sess.struct_span_err(span, &s),
CrateError::LocatorCombined(locator) => {
let crate_name = locator.crate_name;
- let add = match &locator.root {
+ let add_info = match &locator.root {
None => String::new(),
Some(r) => format!(" which `{}` depends on", r.name),
};
- let mut msg = "the following crate versions were found:".to_string();
- let mut err = if !locator.crate_rejections.via_hash.is_empty() {
- let mut err = struct_span_err!(
- sess,
- span,
- E0460,
- "found possibly newer version of crate `{}`{}",
- crate_name,
- add,
- );
- err.note("perhaps that crate needs to be recompiled?");
+ // FIXME: There are no tests for CrateLocationUnknownType or LibFilenameForm
+ if !locator.crate_rejections.via_filename.is_empty() {
+ let mismatches = locator.crate_rejections.via_filename.iter();
+ for CrateMismatch { path, .. } in mismatches {
+ sess.emit_err(CrateLocationUnknownType { span, path: &path });
+ sess.emit_err(LibFilenameForm {
+ span,
+ dll_prefix: &locator.dll_prefix,
+ dll_suffix: &locator.dll_suffix,
+ });
+ }
+ }
+ let mut found_crates = String::new();
+ if !locator.crate_rejections.via_hash.is_empty() {
let mismatches = locator.crate_rejections.via_hash.iter();
for CrateMismatch { path, .. } in mismatches {
- msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
+ found_crates.push_str(&format!(
+ "\ncrate `{}`: {}",
+ crate_name,
+ path.display()
+ ));
}
if let Some(r) = locator.root {
for path in r.source.paths() {
- msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display()));
+ found_crates.push_str(&format!(
+ "\ncrate `{}`: {}",
+ r.name,
+ path.display()
+ ));
}
}
- err.note(&msg);
- err
- } else if !locator.crate_rejections.via_triple.is_empty() {
- let mut err = struct_span_err!(
- sess,
+ sess.emit_err(NewerCrateVersion {
span,
- E0461,
- "couldn't find crate `{}` with expected target triple {}{}",
- crate_name,
- locator.triple,
- add,
- );
+ crate_name: crate_name,
+ add_info,
+ found_crates,
+ });
+ } else if !locator.crate_rejections.via_triple.is_empty() {
let mismatches = locator.crate_rejections.via_triple.iter();
for CrateMismatch { path, got } in mismatches {
- msg.push_str(&format!(
+ found_crates.push_str(&format!(
"\ncrate `{}`, target triple {}: {}",
crate_name,
got,
path.display(),
));
}
- err.note(&msg);
- err
- } else if !locator.crate_rejections.via_kind.is_empty() {
- let mut err = struct_span_err!(
- sess,
+ sess.emit_err(NoCrateWithTriple {
span,
- E0462,
- "found staticlib `{}` instead of rlib or dylib{}",
- crate_name,
- add,
- );
- err.help("please recompile that crate using --crate-type lib");
+ crate_name: crate_name,
+ locator_triple: locator.triple.triple(),
+ add_info,
+ found_crates,
+ });
+ } else if !locator.crate_rejections.via_kind.is_empty() {
let mismatches = locator.crate_rejections.via_kind.iter();
for CrateMismatch { path, .. } in mismatches {
- msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
+ found_crates.push_str(&format!(
+ "\ncrate `{}`: {}",
+ crate_name,
+ path.display()
+ ));
}
- err.note(&msg);
- err
+ sess.emit_err(FoundStaticlib { span, crate_name, add_info, found_crates });
} else if !locator.crate_rejections.via_version.is_empty() {
- let mut err = struct_span_err!(
- sess,
- span,
- E0514,
- "found crate `{}` compiled by an incompatible version of rustc{}",
- crate_name,
- add,
- );
- err.help(&format!(
- "please recompile that crate using this compiler ({}) \
- (consider running `cargo clean` first)",
- rustc_version(),
- ));
let mismatches = locator.crate_rejections.via_version.iter();
for CrateMismatch { path, got } in mismatches {
- msg.push_str(&format!(
+ found_crates.push_str(&format!(
"\ncrate `{}` compiled by {}: {}",
crate_name,
got,
path.display(),
));
}
- err.note(&msg);
- err
- } else if !locator.crate_rejections.via_invalid.is_empty() {
- let mut err = struct_span_err!(
- sess,
+ sess.emit_err(IncompatibleRustc {
span,
- E0786,
- "found invalid metadata files for crate `{}`{}",
crate_name,
- add,
- );
+ add_info,
+ found_crates,
+ rustc_version: rustc_version(),
+ });
+ } else if !locator.crate_rejections.via_invalid.is_empty() {
+ let mut crate_rejections = Vec::new();
for CrateMismatch { path: _, got } in locator.crate_rejections.via_invalid {
- err.note(&got);
+ crate_rejections.push(got);
}
- err
+ sess.emit_err(InvalidMetadataFiles {
+ span,
+ crate_name,
+ add_info,
+ crate_rejections,
+ });
} else {
- let mut err = struct_span_err!(
- sess,
+ sess.emit_err(CannotFindCrate {
span,
- E0463,
- "can't find crate for `{}`{}",
crate_name,
- add,
- );
-
- if (crate_name == sym::std || crate_name == sym::core)
- && locator.triple != TargetTriple::from_triple(config::host_triple())
- {
- if missing_core {
- err.note(&format!(
- "the `{}` target may not be installed",
- locator.triple
- ));
- } else {
- err.note(&format!(
- "the `{}` target may not support the standard library",
- locator.triple
- ));
- }
- // NOTE: this suggests using rustup, even though the user may not have it installed.
- // That's because they could choose to install it; or this may give them a hint which
- // target they need to install from their distro.
- if missing_core {
- err.help(&format!(
- "consider downloading the target with `rustup target add {}`",
- locator.triple
- ));
- }
- // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway.
- // NOTE: this is a dummy span if `extern crate std` was injected by the compiler.
- // If it's not a dummy, that means someone added `extern crate std` explicitly and `#![no_std]` won't help.
- if !missing_core && span.is_dummy() {
- let current_crate =
- sess.opts.crate_name.as_deref().unwrap_or("<unknown>");
- err.note(&format!(
- "`std` is required by `{}` because it does not declare `#![no_std]`",
- current_crate
- ));
- }
- if sess.is_nightly_build() {
- err.help("consider building the standard library from source with `cargo build -Zbuild-std`");
- }
- } else if crate_name
- == Symbol::intern(&sess.opts.unstable_opts.profiler_runtime)
- {
- err.note("the compiler may have been built without the profiler runtime");
- } else if crate_name.as_str().starts_with("rustc_") {
- err.help(
- "maybe you need to install the missing components with: \
- `rustup component add rust-src rustc-dev llvm-tools-preview`",
- );
- }
- err.span_label(span, "can't find crate");
- err
- };
-
- if !locator.crate_rejections.via_filename.is_empty() {
- let mismatches = locator.crate_rejections.via_filename.iter();
- for CrateMismatch { path, .. } in mismatches {
- err.note(&format!(
- "extern location for {} is of an unknown type: {}",
- crate_name,
- path.display(),
- ))
- .help(&format!(
- "file name should be lib*.rlib or {}*.{}",
- locator.dll_prefix, locator.dll_suffix
- ));
- }
+ add_info,
+ missing_core,
+ current_crate: sess
+ .opts
+ .crate_name
+ .clone()
+ .unwrap_or("<unknown>".to_string()),
+ is_nightly_build: sess.is_nightly_build(),
+ profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime),
+ locator_triple: locator.triple,
+ });
}
- err
}
- CrateError::NonDylibPlugin(crate_name) => struct_span_err!(
- sess,
- span,
- E0457,
- "plugin `{}` only found in rlib format, but must be available in dylib format",
- crate_name,
- ),
- };
-
- diag.emit();
+ CrateError::NonDylibPlugin(crate_name) => {
+ sess.emit_err(NoDylibPlugin { span, crate_name });
+ }
+ }
}
}
use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
use rustc_attr as attr;
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
use rustc_span::symbol::{sym, Symbol};
use rustc_target::spec::abi::Abi;
+use crate::errors::{
+ AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, EmptyRenamingTarget,
+ FrameworkOnlyWindows, ImportNameTypeForm, ImportNameTypeRaw, ImportNameTypeX86,
+ IncompatibleWasmLink, InvalidLinkModifier, LibFrameworkApple, LinkCfgForm,
+ LinkCfgSinglePredicate, LinkFrameworkApple, LinkKindForm, LinkModifiersForm, LinkNameForm,
+ LinkOrdinalRawDylib, LinkRequiresName, MultipleCfgs, MultipleImportNameType,
+ MultipleKindsInLink, MultipleLinkModifiers, MultipleModifiers, MultipleNamesInLink,
+ MultipleRenamings, MultipleWasmImport, NoLinkModOverride, RawDylibNoNul, RenamingNoLink,
+ UnexpectedLinkArg, UnknownImportNameType, UnknownLinkKind, UnknownLinkModifier, UnsupportedAbi,
+ UnsupportedAbiI686, WasmImportForm, WholeArchiveNeedsStatic,
+};
+
pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
let mut collector = Collector { tcx, libs: Vec::new() };
for id in tcx.hir().items() {
match item.name_or_empty() {
sym::name => {
if name.is_some() {
- let msg = "multiple `name` arguments in a single `#[link]` attribute";
- sess.span_err(item.span(), msg);
+ sess.emit_err(MultipleNamesInLink { span: item.span() });
continue;
}
let Some(link_name) = item.value_str() else {
- let msg = "link name must be of the form `name = \"string\"`";
- sess.span_err(item.span(), msg);
+ sess.emit_err(LinkNameForm { span: item.span() });
continue;
};
let span = item.name_value_literal_span().unwrap();
if link_name.is_empty() {
- struct_span_err!(sess, span, E0454, "link name must not be empty")
- .span_label(span, "empty link name")
- .emit();
+ sess.emit_err(EmptyLinkName { span });
}
name = Some((link_name, span));
}
sym::kind => {
if kind.is_some() {
- let msg = "multiple `kind` arguments in a single `#[link]` attribute";
- sess.span_err(item.span(), msg);
+ sess.emit_err(MultipleKindsInLink { span: item.span() });
continue;
}
let Some(link_kind) = item.value_str() else {
- let msg = "link kind must be of the form `kind = \"string\"`";
- sess.span_err(item.span(), msg);
+ sess.emit_err(LinkKindForm { span: item.span() });
continue;
};
"dylib" => NativeLibKind::Dylib { as_needed: None },
"framework" => {
if !sess.target.is_like_osx {
- struct_span_err!(
- sess,
- span,
- E0455,
- "link kind `framework` is only supported on Apple targets"
- )
- .emit();
+ sess.emit_err(LinkFrameworkApple { span });
}
NativeLibKind::Framework { as_needed: None }
}
"raw-dylib" => {
if !sess.target.is_like_windows {
- struct_span_err!(
- sess,
- span,
- E0455,
- "link kind `raw-dylib` is only supported on Windows targets"
- )
- .emit();
+ sess.emit_err(FrameworkOnlyWindows { span });
} else if !features.raw_dylib {
feature_err(
&sess.parse_sess,
NativeLibKind::RawDylib
}
kind => {
- let msg = format!(
- "unknown link kind `{kind}`, expected one of: \
- static, dylib, framework, raw-dylib"
- );
- struct_span_err!(sess, span, E0458, "{}", msg)
- .span_label(span, "unknown link kind")
- .emit();
+ sess.emit_err(UnknownLinkKind { span, kind });
continue;
}
};
}
sym::modifiers => {
if modifiers.is_some() {
- let msg =
- "multiple `modifiers` arguments in a single `#[link]` attribute";
- sess.span_err(item.span(), msg);
+ sess.emit_err(MultipleLinkModifiers { span: item.span() });
continue;
}
let Some(link_modifiers) = item.value_str() else {
- let msg = "link modifiers must be of the form `modifiers = \"string\"`";
- sess.span_err(item.span(), msg);
+ sess.emit_err(LinkModifiersForm { span: item.span() });
continue;
};
modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
}
sym::cfg => {
if cfg.is_some() {
- let msg = "multiple `cfg` arguments in a single `#[link]` attribute";
- sess.span_err(item.span(), msg);
+ sess.emit_err(MultipleCfgs { span: item.span() });
continue;
}
let Some(link_cfg) = item.meta_item_list() else {
- let msg = "link cfg must be of the form `cfg(/* predicate */)`";
- sess.span_err(item.span(), msg);
+ sess.emit_err(LinkCfgForm { span: item.span() });
continue;
};
let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
- let msg = "link cfg must have a single predicate argument";
- sess.span_err(item.span(), msg);
+ sess.emit_err(LinkCfgSinglePredicate { span: item.span() });
continue;
};
if !features.link_cfg {
}
sym::wasm_import_module => {
if wasm_import_module.is_some() {
- let msg = "multiple `wasm_import_module` arguments \
- in a single `#[link]` attribute";
- sess.span_err(item.span(), msg);
+ sess.emit_err(MultipleWasmImport { span: item.span() });
continue;
}
let Some(link_wasm_import_module) = item.value_str() else {
- let msg = "wasm import module must be of the form \
- `wasm_import_module = \"string\"`";
- sess.span_err(item.span(), msg);
+ sess.emit_err(WasmImportForm { span: item.span() });
continue;
};
wasm_import_module = Some((link_wasm_import_module, item.span()));
}
sym::import_name_type => {
if import_name_type.is_some() {
- let msg = "multiple `import_name_type` arguments in a single `#[link]` attribute";
- sess.span_err(item.span(), msg);
+ sess.emit_err(MultipleImportNameType { span: item.span() });
continue;
}
let Some(link_import_name_type) = item.value_str() else {
- let msg = "import name type must be of the form `import_name_type = \"string\"`";
- sess.span_err(item.span(), msg);
+ sess.emit_err(ImportNameTypeForm { span: item.span() });
continue;
};
if self.tcx.sess.target.arch != "x86" {
- let msg = "import name type is only supported on x86";
- sess.span_err(item.span(), msg);
+ sess.emit_err(ImportNameTypeX86 { span: item.span() });
continue;
}
"noprefix" => PeImportNameType::NoPrefix,
"undecorated" => PeImportNameType::Undecorated,
import_name_type => {
- let msg = format!(
- "unknown import name type `{import_name_type}`, expected one of: \
- decorated, noprefix, undecorated"
- );
- sess.span_err(item.span(), msg);
+ sess.emit_err(UnknownImportNameType {
+ span: item.span(),
+ import_name_type,
+ });
continue;
}
};
import_name_type = Some((link_import_name_type, item.span()));
}
_ => {
- let msg = "unexpected `#[link]` argument, expected one of: \
- name, kind, modifiers, cfg, wasm_import_module, import_name_type";
- sess.span_err(item.span(), msg);
+ sess.emit_err(UnexpectedLinkArg { span: item.span() });
}
}
}
let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
Some(m) => (m, modifier.starts_with('+')),
None => {
- sess.span_err(
- span,
- "invalid linking modifier syntax, expected '+' or '-' prefix \
- before one of: bundle, verbatim, whole-archive, as-needed",
- );
+ sess.emit_err(InvalidLinkModifier { span });
continue;
}
};
}
let assign_modifier = |dst: &mut Option<bool>| {
if dst.is_some() {
- let msg = format!(
- "multiple `{modifier}` modifiers in a single `modifiers` argument"
- );
- sess.span_err(span, &msg);
+ sess.emit_err(MultipleModifiers { span, modifier });
} else {
*dst = Some(value);
}
assign_modifier(bundle)
}
("bundle", _) => {
- sess.span_err(
- span,
- "linking modifier `bundle` is only compatible with \
- `static` linking kind",
- );
+ sess.emit_err(BundleNeedsStatic { span });
}
("verbatim", _) => {
assign_modifier(whole_archive)
}
("whole-archive", _) => {
- sess.span_err(
- span,
- "linking modifier `whole-archive` is only compatible with \
- `static` linking kind",
- );
+ sess.emit_err(WholeArchiveNeedsStatic { span });
}
("as-needed", Some(NativeLibKind::Dylib { as_needed }))
assign_modifier(as_needed)
}
("as-needed", _) => {
- sess.span_err(
- span,
- "linking modifier `as-needed` is only compatible with \
- `dylib` and `framework` linking kinds",
- );
+ sess.emit_err(AsNeededCompatibility { span });
}
_ => {
- sess.span_err(
- span,
- format!(
- "unknown linking modifier `{modifier}`, expected one of: \
- bundle, verbatim, whole-archive, as-needed"
- ),
- );
+ sess.emit_err(UnknownLinkModifier { span, modifier });
}
}
}
if let Some((_, span)) = wasm_import_module {
if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
- let msg = "`wasm_import_module` is incompatible with \
- other arguments in `#[link]` attributes";
- sess.span_err(span, msg);
+ sess.emit_err(IncompatibleWasmLink { span });
}
} else if name.is_none() {
- struct_span_err!(
- sess,
- m.span,
- E0459,
- "`#[link]` attribute requires a `name = \"string\"` argument"
- )
- .span_label(m.span, "missing `name` argument")
- .emit();
+ sess.emit_err(LinkRequiresName { span: m.span });
}
// Do this outside of the loop so that `import_name_type` can be specified before `kind`.
if let Some((_, span)) = import_name_type {
if kind != Some(NativeLibKind::RawDylib) {
- let msg = "import name type can only be used with link kind `raw-dylib`";
- sess.span_err(span, msg);
+ sess.emit_err(ImportNameTypeRaw { span });
}
}
let dll_imports = match kind {
Some(NativeLibKind::RawDylib) => {
if let Some((name, span)) = name && name.as_str().contains('\0') {
- sess.span_err(
- span,
- "link name must not contain NUL characters if link kind is `raw-dylib`",
- );
+ sess.emit_err(RawDylibNoNul { span });
}
foreign_mod_items
.iter()
.iter()
.find(|a| a.has_name(sym::link_ordinal))
.unwrap();
- sess.span_err(
- link_ordinal_attr.span,
- "`#[link_ordinal]` is only supported if link kind is `raw-dylib`",
- );
+ sess.emit_err(LinkOrdinalRawDylib { span: link_ordinal_attr.span });
}
}
for lib in &self.tcx.sess.opts.libs {
if let NativeLibKind::Framework { .. } = lib.kind && !self.tcx.sess.target.is_like_osx {
// Cannot check this when parsing options because the target is not yet available.
- self.tcx.sess.err("library kind `framework` is only supported on Apple targets");
+ self.tcx.sess.emit_err(LibFrameworkApple);
}
if let Some(ref new_name) = lib.new_name {
let any_duplicate = self
.filter_map(|lib| lib.name.as_ref())
.any(|n| n.as_str() == lib.name);
if new_name.is_empty() {
- self.tcx.sess.err(format!(
- "an empty renaming target was specified for library `{}`",
- lib.name
- ));
+ self.tcx.sess.emit_err(EmptyRenamingTarget { lib_name: &lib.name });
} else if !any_duplicate {
- self.tcx.sess.err(format!(
- "renaming of the library `{}` was specified, \
- however this crate contains no `#[link(...)]` \
- attributes referencing this library",
- lib.name
- ));
+ self.tcx.sess.emit_err(RenamingNoLink { lib_name: &lib.name });
} else if !renames.insert(&lib.name) {
- self.tcx.sess.err(format!(
- "multiple renamings were \
- specified for library `{}`",
- lib.name
- ));
+ self.tcx.sess.emit_err(MultipleRenamings { lib_name: &lib.name });
}
}
}
// involved or not, library reordering and kind overriding without
// explicit `:rename` in particular.
if lib.has_modifiers() || passed_lib.has_modifiers() {
- let msg = "overriding linking modifiers from command line is not supported";
match lib.foreign_module {
- Some(def_id) => self.tcx.sess.span_err(self.tcx.def_span(def_id), msg),
- None => self.tcx.sess.err(msg),
+ Some(def_id) => self.tcx.sess.emit_err(NoLinkModOverride {
+ span: Some(self.tcx.def_span(def_id)),
+ }),
+ None => {
+ self.tcx.sess.emit_err(NoLinkModOverride { span: None })
+ }
};
}
if passed_lib.kind != NativeLibKind::Unspecified {
DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
}
_ => {
- self.tcx.sess.span_fatal(
- item.span,
- r#"ABI not supported by `#[link(kind = "raw-dylib")]` on i686"#,
- );
+ self.tcx.sess.emit_fatal(UnsupportedAbiI686 { span: item.span });
}
}
} else {
match abi {
Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C,
_ => {
- self.tcx.sess.span_fatal(
- item.span,
- r#"ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture"#,
- );
+ self.tcx.sess.emit_fatal(UnsupportedAbi { span: item.span });
}
}
};
use crate::rmeta::*;
use rustc_ast as ast;
-use rustc_ast::ptr::P;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::svh::Svh;
use rustc_session::Session;
use rustc_span::hygiene::{ExpnIndex, MacroKind};
use rustc_span::source_map::{respan, Spanned};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{self, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP};
use proc_macro::bridge::client::ProcMacro;
use std::mem;
use std::num::NonZeroUsize;
use std::path::Path;
-use tracing::debug;
pub(super) use cstore_impl::provide;
pub use cstore_impl::provide_extern;
self.opt_item_ident(item_index, sess).expect("no encoded ident for item")
}
- fn maybe_kind(self, item_id: DefIndex) -> Option<EntryKind> {
- self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
- }
-
#[inline]
pub(super) fn map_encoded_cnum_to_current(self, cnum: CrateNum) -> CrateNum {
if cnum == LOCAL_CRATE { self.cnum } else { self.cnum_map[cnum] }
}
- fn kind(self, item_id: DefIndex) -> EntryKind {
- self.maybe_kind(item_id).unwrap_or_else(|| {
- bug!(
- "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
- item_id,
- self.root.name,
- self.cnum,
- )
- })
- }
-
fn def_kind(self, item_id: DefIndex) -> DefKind {
self.root.tables.opt_def_kind.get(self, item_id).unwrap_or_else(|| {
bug!(
)
}
- fn get_variant(self, kind: &EntryKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef {
- let data = match kind {
- EntryKind::Variant(data) | EntryKind::Struct(data) | EntryKind::Union(data) => {
- data.decode(self)
- }
- _ => bug!(),
- };
-
+ fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef {
let adt_kind = match kind {
- EntryKind::Variant(_) => ty::AdtKind::Enum,
- EntryKind::Struct(..) => ty::AdtKind::Struct,
- EntryKind::Union(..) => ty::AdtKind::Union,
+ DefKind::Variant => ty::AdtKind::Enum,
+ DefKind::Struct => ty::AdtKind::Struct,
+ DefKind::Union => ty::AdtKind::Union,
_ => bug!(),
};
+ let data = self.root.tables.variant_data.get(self, index).unwrap().decode(self);
+
let variant_did =
if adt_kind == ty::AdtKind::Enum { Some(self.local_def_id(index)) } else { None };
let ctor_did = data.ctor.map(|index| self.local_def_id(index));
}
fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> {
- let kind = self.kind(item_id);
+ let kind = self.def_kind(item_id);
let did = self.local_def_id(item_id);
let adt_kind = match kind {
- EntryKind::Enum => ty::AdtKind::Enum,
- EntryKind::Struct(_) => ty::AdtKind::Struct,
- EntryKind::Union(_) => ty::AdtKind::Union,
+ DefKind::Enum => ty::AdtKind::Enum,
+ DefKind::Struct => ty::AdtKind::Struct,
+ DefKind::Union => ty::AdtKind::Union,
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
};
let repr = self.root.tables.repr_options.get(self, item_id).unwrap().decode(self);
.get(self, item_id)
.unwrap_or_else(LazyArray::empty)
.decode(self)
- .map(|index| self.get_variant(&self.kind(index), index, did))
+ .map(|index| self.get_variant(&self.def_kind(index), index, did))
.collect()
} else {
std::iter::once(self.get_variant(&kind, item_id, did)).collect()
let vis = self.get_visibility(child_index);
let span = self.get_span(child_index, sess);
let macro_rules = match kind {
- DefKind::Macro(..) => match self.kind(child_index) {
- EntryKind::MacroDef(_, macro_rules) => macro_rules,
- _ => unreachable!(),
- },
+ DefKind::Macro(..) => {
+ self.root.tables.macro_rules.get(self, child_index).is_some()
+ }
_ => false,
};
}
}
- match self.kind(id) {
- EntryKind::Mod(exports) => {
- for exp in exports.decode((self, sess)) {
- callback(exp);
- }
+ if let Some(exports) = self.root.tables.module_reexports.get(self, id) {
+ for exp in exports.decode((self, sess)) {
+ callback(exp);
}
- EntryKind::Enum | EntryKind::Trait => {}
- _ => bug!("`for_each_module_child` is called on a non-module: {:?}", self.def_kind(id)),
}
}
}
fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId {
- match self.kind(id) {
- EntryKind::Mod(_) | EntryKind::Enum | EntryKind::Trait => {
- self.get_expn_that_defined(id, sess)
- }
+ match self.def_kind(id) {
+ DefKind::Mod | DefKind::Enum | DefKind::Trait => self.get_expn_that_defined(id, sess),
_ => panic!("Expected module, found {:?}", self.local_def_id(id)),
}
}
- fn get_fn_has_self_parameter(self, id: DefIndex) -> bool {
- match self.kind(id) {
- EntryKind::AssocFn { has_self, .. } => has_self,
- _ => false,
- }
+ fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool {
+ self.root
+ .tables
+ .fn_arg_names
+ .get(self, id)
+ .unwrap_or_else(LazyArray::empty)
+ .decode((self, sess))
+ .nth(0)
+ .map_or(false, |ident| ident.name == kw::SelfLower)
}
fn get_associated_item_def_ids(
.map(move |child_index| self.local_def_id(child_index))
}
- fn get_associated_item(self, id: DefIndex) -> ty::AssocItem {
+ fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem {
let name = self.item_name(id);
- let (kind, container, has_self) = match self.kind(id) {
- EntryKind::AssocConst(container) => (ty::AssocKind::Const, container, false),
- EntryKind::AssocFn { container, has_self } => (ty::AssocKind::Fn, container, has_self),
- EntryKind::AssocType(container) => (ty::AssocKind::Type, container, false),
- _ => bug!("cannot get associated-item of `{:?}`", id),
+ let kind = match self.def_kind(id) {
+ DefKind::AssocConst => ty::AssocKind::Const,
+ DefKind::AssocFn => ty::AssocKind::Fn,
+ DefKind::AssocTy => ty::AssocKind::Type,
+ _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
};
+ let has_self = self.get_fn_has_self_parameter(id, sess);
+ let container = self.root.tables.assoc_container.get(self, id).unwrap();
ty::AssocItem {
name,
}
fn get_ctor_def_id_and_kind(self, node_id: DefIndex) -> Option<(DefId, CtorKind)> {
- match self.kind(node_id) {
- EntryKind::Struct(data) | EntryKind::Variant(data) => {
- let vdata = data.decode(self);
+ match self.def_kind(node_id) {
+ DefKind::Struct | DefKind::Variant => {
+ let vdata = self.root.tables.variant_data.get(self, node_id).unwrap().decode(self);
vdata.ctor.map(|index| (self.local_def_id(index), vdata.ctor_kind))
}
_ => None,
}
fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef {
- match self.kind(id) {
- EntryKind::MacroDef(mac_args, macro_rules) => {
- ast::MacroDef { body: P(mac_args.decode((self, sess))), macro_rules }
+ match self.def_kind(id) {
+ DefKind::Macro(_) => {
+ let macro_rules = self.root.tables.macro_rules.get(self, id).is_some();
+ let body =
+ self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess));
+ ast::MacroDef { macro_rules, body: ast::ptr::P(body) }
}
_ => bug!(),
}
}
fn is_foreign_item(self, id: DefIndex) -> bool {
- match self.kind(id) {
- EntryKind::ForeignStatic | EntryKind::ForeignFn => true,
- _ => false,
+ if let Some(parent) = self.def_key(id).parent {
+ matches!(self.def_kind(parent), DefKind::ForeignMod)
+ } else {
+ false
}
}
associated_item_def_ids => {
tcx.arena.alloc_from_iter(cdata.get_associated_item_def_ids(def_id.index, tcx.sess))
}
- associated_item => { cdata.get_associated_item(def_id.index) }
+ associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) }
inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
is_foreign_item => { cdata.is_foreign_item(def_id.index) }
item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
)
}
- pub fn fn_has_self_parameter_untracked(&self, def: DefId) -> bool {
- self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index)
+ pub fn fn_has_self_parameter_untracked(&self, def: DefId, sess: &Session) -> bool {
+ self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index, sess)
}
pub fn crate_source_untracked(&self, cnum: CrateNum) -> Lrc<CrateSource> {
+use crate::errors::{FailCreateFileEncoder, FailSeekFile, FailWriteFile};
use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
use crate::rmeta::table::TableBuilder;
use crate::rmeta::*;
use rustc_hir::definitions::DefPathData;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::lang_items;
-use rustc_hir::{AnonConst, GenericParamKind};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::{
use std::iter;
use std::num::NonZeroUsize;
use std::path::{Path, PathBuf};
-use tracing::{debug, trace};
pub(super) struct EncodeContext<'a, 'tcx> {
opaque: opaque::FileEncoder,
}
}
+fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> bool {
+ match def_kind {
+ DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::Variant
+ | DefKind::Ctor(..)
+ | DefKind::Field
+ | DefKind::Fn
+ | DefKind::Const
+ | DefKind::Static(..)
+ | DefKind::TyAlias
+ | DefKind::OpaqueTy
+ | DefKind::ForeignTy
+ | DefKind::Impl
+ | DefKind::AssocFn
+ | DefKind::AssocConst
+ | DefKind::Closure
+ | DefKind::Generator
+ | DefKind::ConstParam
+ | DefKind::AnonConst
+ | DefKind::InlineConst => true,
+
+ DefKind::AssocTy => {
+ let assoc_item = tcx.associated_item(def_id);
+ match assoc_item.container {
+ ty::AssocItemContainer::ImplContainer => true,
+ ty::AssocItemContainer::TraitContainer => assoc_item.defaultness(tcx).has_value(),
+ }
+ }
+ DefKind::TyParam => {
+ let hir::Node::GenericParam(param) = tcx.hir().get_by_def_id(def_id) else { bug!() };
+ let hir::GenericParamKind::Type { default, .. } = param.kind else { bug!() };
+ default.is_some()
+ }
+
+ DefKind::Trait
+ | DefKind::TraitAlias
+ | DefKind::Mod
+ | DefKind::ForeignMod
+ | DefKind::Macro(..)
+ | DefKind::Use
+ | DefKind::LifetimeParam
+ | DefKind::GlobalAsm
+ | DefKind::ExternCrate => false,
+ }
+}
+
+fn should_encode_const(def_kind: DefKind) -> bool {
+ match def_kind {
+ DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => true,
+
+ DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::Variant
+ | DefKind::Ctor(..)
+ | DefKind::Field
+ | DefKind::Fn
+ | DefKind::Static(..)
+ | DefKind::TyAlias
+ | DefKind::OpaqueTy
+ | DefKind::ForeignTy
+ | DefKind::Impl
+ | DefKind::AssocFn
+ | DefKind::Closure
+ | DefKind::Generator
+ | DefKind::ConstParam
+ | DefKind::InlineConst
+ | DefKind::AssocTy
+ | DefKind::TyParam
+ | DefKind::Trait
+ | DefKind::TraitAlias
+ | DefKind::Mod
+ | DefKind::ForeignMod
+ | DefKind::Macro(..)
+ | DefKind::Use
+ | DefKind::LifetimeParam
+ | DefKind::GlobalAsm
+ | DefKind::ExternCrate => false,
+ }
+}
+
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_attrs(&mut self, def_id: LocalDefId) {
let mut attrs = self
let def_kind = tcx.opt_def_kind(local_id);
let Some(def_kind) = def_kind else { continue };
self.tables.opt_def_kind.set(def_id.index, def_kind);
- record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
+ let def_span = tcx.def_span(local_id);
+ record!(self.tables.def_span[def_id] <- def_span);
self.encode_attrs(local_id);
record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
if let Some(ident_span) = tcx.def_ident_span(def_id) {
record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
}
}
- if let DefKind::TyParam | DefKind::ConstParam = def_kind {
- if let Some(default) = self.tcx.object_lifetime_default(def_id) {
- record!(self.tables.object_lifetime_default[def_id] <- default);
- }
+ if should_encode_type(tcx, local_id, def_kind) {
+ record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id));
+ }
+ if let DefKind::TyParam = def_kind {
+ let default = self.tcx.object_lifetime_default(def_id);
+ record!(self.tables.object_lifetime_default[def_id] <- default);
}
if let DefKind::Trait | DefKind::TraitAlias = def_kind {
record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
}
}
- fn encode_item_type(&mut self, def_id: DefId) {
- debug!("EncodeContext::encode_item_type({:?})", def_id);
- record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id));
- }
-
fn encode_enum_variant_info(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) {
let tcx = self.tcx;
let variant = &def.variant(index);
is_non_exhaustive: variant.is_field_list_non_exhaustive(),
};
- record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
+ record!(self.tables.variant_data[def_id] <- data);
self.tables.constness.set(def_id.index, hir::Constness::Const);
record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
assert!(f.did.is_local());
f.did.index
}));
- self.encode_item_type(def_id);
if variant.ctor_kind == CtorKind::Fn {
// FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
if let Some(ctor_def_id) = variant.ctor_def_id {
is_non_exhaustive: variant.is_field_list_non_exhaustive(),
};
- record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
+ record!(self.tables.variant_data[def_id] <- data);
self.tables.constness.set(def_id.index, hir::Constness::Const);
- self.encode_item_type(def_id);
if variant.ctor_kind == CtorKind::Fn {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
}
// code uses it). However, we skip encoding anything relating to child
// items - we encode information about proc-macros later on.
let reexports = if !self.is_proc_macro {
- match tcx.module_reexports(local_def_id) {
- Some(exports) => self.lazy_array(exports),
- _ => LazyArray::empty(),
- }
+ tcx.module_reexports(local_def_id).unwrap_or(&[])
} else {
- LazyArray::empty()
+ &[]
};
- record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
+ record_array!(self.tables.module_reexports[def_id] <- reexports);
if self.is_proc_macro {
// Encode this here because we don't do it in encode_def_ids.
record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
}
}
- fn encode_field(
- &mut self,
- adt_def: ty::AdtDef<'tcx>,
- variant_index: VariantIdx,
- field_index: usize,
- ) {
- let variant = &adt_def.variant(variant_index);
- let field = &variant.fields[field_index];
-
- let def_id = field.did;
- debug!("EncodeContext::encode_field({:?})", def_id);
-
- record!(self.tables.kind[def_id] <- EntryKind::Field);
- self.encode_item_type(def_id);
- }
-
fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>, def_id: DefId) {
debug!("EncodeContext::encode_struct_ctor({:?})", def_id);
let tcx = self.tcx;
};
record!(self.tables.repr_options[def_id] <- adt_def.repr());
+ record!(self.tables.variant_data[def_id] <- data);
self.tables.constness.set(def_id.index, hir::Constness::Const);
- record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data)));
- self.encode_item_type(def_id);
if variant.ctor_kind == CtorKind::Fn {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
}
let ast_item = tcx.hir().expect_trait_item(def_id.expect_local());
self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
let trait_item = tcx.associated_item(def_id);
+ self.tables.assoc_container.set(def_id.index, trait_item.container);
match trait_item.kind {
- ty::AssocKind::Const => {
- let rendered = rustc_hir_pretty::to_string(
- &(&self.tcx.hir() as &dyn intravisit::Map<'_>),
- |s| s.print_trait_item(ast_item),
- );
-
- record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::TraitContainer));
- record!(self.tables.mir_const_qualif[def_id] <- mir::ConstQualifs::default());
- record!(self.tables.rendered_const[def_id] <- rendered);
- }
+ ty::AssocKind::Const => {}
ty::AssocKind::Fn => {
let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind else { bug!() };
match *m {
};
self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
self.tables.constness.set(def_id.index, hir::Constness::NotConst);
- record!(self.tables.kind[def_id] <- EntryKind::AssocFn {
- container: ty::AssocItemContainer::TraitContainer,
- has_self: trait_item.fn_has_self_parameter,
- });
}
ty::AssocKind::Type => {
self.encode_explicit_item_bounds(def_id);
- record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::TraitContainer));
- }
- }
- match trait_item.kind {
- ty::AssocKind::Const | ty::AssocKind::Fn => {
- self.encode_item_type(def_id);
- }
- ty::AssocKind::Type => {
- if ast_item.defaultness.has_value() {
- self.encode_item_type(def_id);
- }
}
}
if trait_item.kind == ty::AssocKind::Fn {
let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
let impl_item = self.tcx.associated_item(def_id);
+ self.tables.assoc_container.set(def_id.index, impl_item.container);
match impl_item.kind {
- ty::AssocKind::Const => {
- if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind {
- let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id);
- let const_data = self.encode_rendered_const_for_body(body_id);
-
- record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::ImplContainer));
- record!(self.tables.mir_const_qualif[def_id] <- qualifs);
- record!(self.tables.rendered_const[def_id] <- const_data);
- } else {
- bug!()
- }
- }
ty::AssocKind::Fn => {
let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
self.tables.asyncness.set(def_id.index, sig.header.asyncness);
hir::Constness::NotConst
};
self.tables.constness.set(def_id.index, constness);
- record!(self.tables.kind[def_id] <- EntryKind::AssocFn {
- container: ty::AssocItemContainer::ImplContainer,
- has_self: impl_item.fn_has_self_parameter,
- });
- }
- ty::AssocKind::Type => {
- record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::ImplContainer));
}
+ ty::AssocKind::Const | ty::AssocKind::Type => {}
}
- self.encode_item_type(def_id);
if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into());
}
return;
}
- let keys_and_jobs = self
- .tcx
- .mir_keys(())
- .iter()
- .filter_map(|&def_id| {
- let (encode_const, encode_opt) = should_encode_mir(self.tcx, def_id);
- if encode_const || encode_opt {
- Some((def_id, encode_const, encode_opt))
- } else {
- None
- }
- })
- .collect::<Vec<_>>();
- for (def_id, encode_const, encode_opt) in keys_and_jobs.into_iter() {
+ let tcx = self.tcx;
+
+ let keys_and_jobs = tcx.mir_keys(()).iter().filter_map(|&def_id| {
+ let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
+ if encode_const || encode_opt { Some((def_id, encode_const, encode_opt)) } else { None }
+ });
+ for (def_id, encode_const, encode_opt) in keys_and_jobs {
debug_assert!(encode_const || encode_opt);
debug!("EntryBuilder::encode_mir({:?})", def_id);
if encode_opt {
- record!(self.tables.optimized_mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
+ record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id));
}
if encode_const {
- record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
+ record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id));
// FIXME(generic_const_exprs): this feels wrong to have in `encode_mir`
- let abstract_const = self.tcx.thir_abstract_const(def_id);
+ let abstract_const = tcx.thir_abstract_const(def_id);
if let Ok(Some(abstract_const)) = abstract_const {
record!(self.tables.thir_abstract_const[def_id.to_def_id()] <- abstract_const);
}
+
+ if should_encode_const(tcx.def_kind(def_id)) {
+ let qualifs = tcx.mir_const_qualif(def_id);
+ record!(self.tables.mir_const_qualif[def_id.to_def_id()] <- qualifs);
+ let body_id = tcx.hir().maybe_body_owned_by(def_id);
+ if let Some(body_id) = body_id {
+ let const_data = self.encode_rendered_const_for_body(body_id);
+ record!(self.tables.rendered_const[def_id.to_def_id()] <- const_data);
+ }
+ }
}
- record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
+ record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id));
let instance =
ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id()));
- let unused = self.tcx.unused_generic_params(instance);
+ let unused = tcx.unused_generic_params(instance);
if !unused.is_empty() {
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
}
debug!("EncodeContext::encode_info_for_item({:?})", def_id);
- let entry_kind = match item.kind {
- hir::ItemKind::Static(..) => EntryKind::Static,
- hir::ItemKind::Const(_, body_id) => {
- let qualifs = self.tcx.at(item.span).mir_const_qualif(def_id);
- let const_data = self.encode_rendered_const_for_body(body_id);
- record!(self.tables.mir_const_qualif[def_id] <- qualifs);
- record!(self.tables.rendered_const[def_id] <- const_data);
- EntryKind::Const
- }
+ match item.kind {
hir::ItemKind::Fn(ref sig, .., body) => {
self.tables.asyncness.set(def_id.index, sig.header.asyncness);
record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
self.tables.constness.set(def_id.index, sig.header.constness);
- EntryKind::Fn
}
hir::ItemKind::Macro(ref macro_def, _) => {
- EntryKind::MacroDef(self.lazy(&*macro_def.body), macro_def.macro_rules)
+ if macro_def.macro_rules {
+ self.tables.macro_rules.set(def_id.index, ());
+ }
+ record!(self.tables.macro_definition[def_id] <- &*macro_def.body);
}
hir::ItemKind::Mod(ref m) => {
return self.encode_info_for_mod(item.def_id, m);
}
- hir::ItemKind::ForeignMod { .. } => EntryKind::ForeignMod,
- hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm,
- hir::ItemKind::TyAlias(..) => EntryKind::Type,
hir::ItemKind::OpaqueTy(..) => {
self.encode_explicit_item_bounds(def_id);
- EntryKind::OpaqueTy
}
hir::ItemKind::Enum(..) => {
let adt_def = self.tcx.adt_def(def_id);
record!(self.tables.repr_options[def_id] <- adt_def.repr());
- EntryKind::Enum
}
hir::ItemKind::Struct(ref struct_def, _) => {
let adt_def = self.tcx.adt_def(def_id);
.map(|ctor_hir_id| self.tcx.hir().local_def_id(ctor_hir_id).local_def_index);
let variant = adt_def.non_enum_variant();
- EntryKind::Struct(self.lazy(VariantData {
+ record!(self.tables.variant_data[def_id] <- VariantData {
ctor_kind: variant.ctor_kind,
discr: variant.discr,
ctor,
is_non_exhaustive: variant.is_field_list_non_exhaustive(),
- }))
+ });
}
hir::ItemKind::Union(..) => {
let adt_def = self.tcx.adt_def(def_id);
record!(self.tables.repr_options[def_id] <- adt_def.repr());
let variant = adt_def.non_enum_variant();
- EntryKind::Union(self.lazy(VariantData {
+ record!(self.tables.variant_data[def_id] <- VariantData {
ctor_kind: variant.ctor_kind,
discr: variant.discr,
ctor: None,
is_non_exhaustive: variant.is_field_list_non_exhaustive(),
- }))
+ });
}
hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
self.tables.impl_defaultness.set(def_id.index, *defaultness);
let polarity = self.tcx.impl_polarity(def_id);
self.tables.impl_polarity.set(def_id.index, polarity);
-
- EntryKind::Impl
}
hir::ItemKind::Trait(..) => {
let trait_def = self.tcx.trait_def(def_id);
record!(self.tables.trait_def[def_id] <- trait_def);
-
- EntryKind::Trait
}
hir::ItemKind::TraitAlias(..) => {
let trait_def = self.tcx.trait_def(def_id);
record!(self.tables.trait_def[def_id] <- trait_def);
-
- EntryKind::TraitAlias
}
hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {
bug!("cannot encode info for item {:?}", item)
}
+ hir::ItemKind::Static(..)
+ | hir::ItemKind::Const(..)
+ | hir::ItemKind::ForeignMod { .. }
+ | hir::ItemKind::GlobalAsm(..)
+ | hir::ItemKind::TyAlias(..) => {}
};
- record!(self.tables.kind[def_id] <- entry_kind);
// FIXME(eddyb) there should be a nicer way to do this.
match item.kind {
hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <-
}
_ => {}
}
- match item.kind {
- hir::ItemKind::Static(..)
- | hir::ItemKind::Const(..)
- | hir::ItemKind::Fn(..)
- | hir::ItemKind::TyAlias(..)
- | hir::ItemKind::OpaqueTy(..)
- | hir::ItemKind::Enum(..)
- | hir::ItemKind::Struct(..)
- | hir::ItemKind::Union(..)
- | hir::ItemKind::Impl { .. } => self.encode_item_type(def_id),
- _ => {}
- }
if let hir::ItemKind::Fn(..) = item.kind {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
if tcx.is_intrinsic(def_id) {
record!(self.tables.impl_trait_ref[def_id] <- trait_ref);
}
}
- }
+ // In some cases, along with the item itself, we also
+ // encode some sub-items. Usually we want some info from the item
+ // so it's easier to do that here then to wait until we would encounter
+ // normally in the visitor walk.
+ match item.kind {
+ hir::ItemKind::Enum(..) => {
+ let def = self.tcx.adt_def(item.def_id.to_def_id());
+ for (i, variant) in def.variants().iter_enumerated() {
+ self.encode_enum_variant_info(def, i);
- fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) {
- record!(self.tables.kind[def_id] <- kind);
- if encode_type {
- self.encode_item_type(def_id);
+ if let Some(_ctor_def_id) = variant.ctor_def_id {
+ self.encode_enum_variant_ctor(def, i);
+ }
+ }
+ }
+ hir::ItemKind::Struct(ref struct_def, _) => {
+ let def = self.tcx.adt_def(item.def_id.to_def_id());
+ // If the struct has a constructor, encode it.
+ if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
+ let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
+ self.encode_struct_ctor(def, ctor_def_id.to_def_id());
+ }
+ }
+ hir::ItemKind::Impl { .. } => {
+ for &trait_item_def_id in
+ self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
+ {
+ self.encode_info_for_impl_item(trait_item_def_id);
+ }
+ }
+ hir::ItemKind::Trait(..) => {
+ for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
+ {
+ self.encode_info_for_trait_item(item_def_id);
+ }
+ }
+ _ => {}
}
}
ty::Generator(..) => {
let data = self.tcx.generator_kind(def_id).unwrap();
let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data();
- record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Generator);
record!(self.tables.generator_kind[def_id.to_def_id()] <- data);
record!(self.tables.generator_diagnostic_data[def_id.to_def_id()] <- generator_diagnostic_data);
}
- ty::Closure(..) => {
- record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Closure);
+ ty::Closure(_, substs) => {
+ record!(self.tables.fn_sig[def_id.to_def_id()] <- substs.as_closure().sig());
}
_ => bug!("closure that is neither generator nor closure"),
}
- self.encode_item_type(def_id.to_def_id());
- if let ty::Closure(def_id, substs) = *ty.kind() {
- record!(self.tables.fn_sig[def_id] <- substs.as_closure().sig());
- }
- }
-
- fn encode_info_for_anon_const(&mut self, id: hir::HirId) {
- let def_id = self.tcx.hir().local_def_id(id);
- debug!("EncodeContext::encode_info_for_anon_const({:?})", def_id);
- let body_id = self.tcx.hir().body_owned_by(def_id);
- let const_data = self.encode_rendered_const_for_body(body_id);
- let qualifs = self.tcx.mir_const_qualif(def_id);
-
- record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst);
- record!(self.tables.mir_const_qualif[def_id.to_def_id()] <- qualifs);
- record!(self.tables.rendered_const[def_id.to_def_id()] <- const_data);
- self.encode_item_type(def_id.to_def_id());
}
fn encode_native_libraries(&mut self) -> LazyArray<NativeLib> {
let def_id = id.to_def_id();
self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
- record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
+ self.tables.proc_macro.set(def_id.index, macro_kind);
self.encode_attrs(id);
record!(self.tables.def_keys[def_id] <- def_key);
record!(self.tables.def_ident_span[def_id] <- span);
hir::Constness::NotConst
};
self.tables.constness.set(def_id.index, constness);
- record!(self.tables.kind[def_id] <- EntryKind::ForeignFn);
- }
- hir::ForeignItemKind::Static(..) => {
- record!(self.tables.kind[def_id] <- EntryKind::ForeignStatic);
- }
- hir::ForeignItemKind::Type => {
- record!(self.tables.kind[def_id] <- EntryKind::ForeignType);
+ record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
}
+ hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {}
}
- self.encode_item_type(def_id);
if let hir::ForeignItemKind::Fn(..) = nitem.kind {
- record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
if tcx.is_intrinsic(def_id) {
self.tables.is_intrinsic.set(def_id.index, ());
}
intravisit::walk_expr(self, ex);
self.encode_info_for_expr(ex);
}
- fn visit_anon_const(&mut self, c: &'tcx AnonConst) {
- intravisit::walk_anon_const(self, c);
- self.encode_info_for_anon_const(c.hir_id);
- }
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
intravisit::walk_item(self, item);
match item.kind {
hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these
_ => self.encode_info_for_item(item.def_id.to_def_id(), item),
}
- self.encode_addl_info_for_item(item);
}
fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) {
intravisit::walk_foreign_item(self, ni);
}
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
- fn encode_fields(&mut self, adt_def: ty::AdtDef<'tcx>) {
- for (variant_index, variant) in adt_def.variants().iter_enumerated() {
- for (field_index, _field) in variant.fields.iter().enumerate() {
- self.encode_field(adt_def, variant_index, field_index);
- }
- }
- }
-
fn encode_info_for_generics(&mut self, generics: &hir::Generics<'tcx>) {
for param in generics.params {
let def_id = self.tcx.hir().local_def_id(param.hir_id);
match param.kind {
- GenericParamKind::Lifetime { .. } => continue,
- GenericParamKind::Type { default, .. } => {
- self.encode_info_for_generic_param(
- def_id.to_def_id(),
- EntryKind::TypeParam,
- default.is_some(),
- );
- }
- GenericParamKind::Const { ref default, .. } => {
+ hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => {}
+ hir::GenericParamKind::Const { ref default, .. } => {
let def_id = def_id.to_def_id();
- self.encode_info_for_generic_param(def_id, EntryKind::ConstParam, true);
if default.is_some() {
record!(self.tables.const_param_default[def_id] <- self.tcx.const_param_default(def_id))
}
self.encode_info_for_closure(expr.hir_id);
}
}
-
- /// In some cases, along with the item itself, we also
- /// encode some sub-items. Usually we want some info from the item
- /// so it's easier to do that here then to wait until we would encounter
- /// normally in the visitor walk.
- fn encode_addl_info_for_item(&mut self, item: &hir::Item<'_>) {
- match item.kind {
- hir::ItemKind::Static(..)
- | hir::ItemKind::Const(..)
- | hir::ItemKind::Fn(..)
- | hir::ItemKind::Macro(..)
- | hir::ItemKind::Mod(..)
- | hir::ItemKind::ForeignMod { .. }
- | hir::ItemKind::GlobalAsm(..)
- | hir::ItemKind::ExternCrate(..)
- | hir::ItemKind::Use(..)
- | hir::ItemKind::TyAlias(..)
- | hir::ItemKind::OpaqueTy(..)
- | hir::ItemKind::TraitAlias(..) => {
- // no sub-item recording needed in these cases
- }
- hir::ItemKind::Enum(..) => {
- let def = self.tcx.adt_def(item.def_id.to_def_id());
- self.encode_fields(def);
-
- for (i, variant) in def.variants().iter_enumerated() {
- self.encode_enum_variant_info(def, i);
-
- if let Some(_ctor_def_id) = variant.ctor_def_id {
- self.encode_enum_variant_ctor(def, i);
- }
- }
- }
- hir::ItemKind::Struct(ref struct_def, _) => {
- let def = self.tcx.adt_def(item.def_id.to_def_id());
- self.encode_fields(def);
-
- // If the struct has a constructor, encode it.
- if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
- let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
- self.encode_struct_ctor(def, ctor_def_id.to_def_id());
- }
- }
- hir::ItemKind::Union(..) => {
- let def = self.tcx.adt_def(item.def_id.to_def_id());
- self.encode_fields(def);
- }
- hir::ItemKind::Impl { .. } => {
- for &trait_item_def_id in
- self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
- {
- self.encode_info_for_impl_item(trait_item_def_id);
- }
- }
- hir::ItemKind::Trait(..) => {
- for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
- {
- self.encode_info_for_trait_item(item_def_id);
- }
- }
- }
- }
}
/// Used to prefetch queries which will be needed later by metadata encoding.
fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) {
let mut encoder = opaque::FileEncoder::new(path)
- .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to create file encoder: {}", err)));
+ .unwrap_or_else(|err| tcx.sess.emit_fatal(FailCreateFileEncoder { err }));
encoder.emit_raw_bytes(METADATA_HEADER);
// Will be filled with the root position after encoding everything.
// Encode the root position.
let header = METADATA_HEADER.len();
file.seek(std::io::SeekFrom::Start(header as u64))
- .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to seek the file: {}", err)));
+ .unwrap_or_else(|err| tcx.sess.emit_fatal(FailSeekFile { err }));
let pos = root.position.get();
file.write_all(&[(pos >> 24) as u8, (pos >> 16) as u8, (pos >> 8) as u8, (pos >> 0) as u8])
- .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to write to the file: {}", err)));
+ .unwrap_or_else(|err| tcx.sess.emit_fatal(FailWriteFile { err }));
// Return to the position where we are before writing the root position.
file.seek(std::io::SeekFrom::Start(pos_before_seek)).unwrap();
}
define_tables! {
- kind: Table<DefIndex, LazyValue<EntryKind>>,
attributes: Table<DefIndex, LazyArray<ast::Attribute>>,
children: Table<DefIndex, LazyArray<DefIndex>>,
proc_macro_quoted_spans: Table<usize, LazyValue<Span>>,
generator_diagnostic_data: Table<DefIndex, LazyValue<GeneratorDiagnosticData<'static>>>,
may_have_doc_links: Table<DefIndex, ()>,
-}
-
-#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)]
-enum EntryKind {
- AnonConst,
- Const,
- Static,
- ForeignStatic,
- ForeignMod,
- ForeignType,
- GlobalAsm,
- Type,
- TypeParam,
- ConstParam,
- OpaqueTy,
- Enum,
- Field,
- Variant(LazyValue<VariantData>),
- Struct(LazyValue<VariantData>),
- Union(LazyValue<VariantData>),
- Fn,
- ForeignFn,
- Mod(LazyArray<ModChild>),
- MacroDef(LazyValue<ast::MacArgs>, /*macro_rules*/ bool),
- ProcMacro(MacroKind),
- Closure,
- Generator,
- Trait,
- Impl,
- AssocFn { container: ty::AssocItemContainer, has_self: bool },
- AssocType(ty::AssocItemContainer),
- AssocConst(ty::AssocItemContainer),
- TraitAlias,
+ variant_data: Table<DefIndex, LazyValue<VariantData>>,
+ assoc_container: Table<DefIndex, ty::AssocItemContainer>,
+ // Slot is full when macro is macro_rules.
+ macro_rules: Table<DefIndex, ()>,
+ macro_definition: Table<DefIndex, LazyValue<ast::MacArgs>>,
+ proc_macro: Table<DefIndex, MacroKind>,
+ module_reexports: Table<DefIndex, LazyArray<ModChild>>,
}
#[derive(TyEncodable, TyDecodable)]
trivially_parameterized_over_tcx! {
VariantData,
- EntryKind,
RawDefId,
TraitImpls,
IncoherentImpls,
use std::convert::TryInto;
use std::marker::PhantomData;
use std::num::NonZeroUsize;
-use tracing::debug;
/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
/// Used mainly for Lazy positions and lengths.
}
match b[0] - 1 {
$(${index()} => Some($($pat)*),)*
- _ => panic!("Unexpected ImplPolarity code: {:?}", b[0]),
+ _ => panic!("Unexpected {} code: {:?}", stringify!($ty), b[0]),
}
}
}
}
+fixed_size_enum! {
+ ty::AssocItemContainer {
+ ( TraitContainer )
+ ( ImplContainer )
+ }
+}
+
+fixed_size_enum! {
+ MacroKind {
+ ( Attr )
+ ( Bang )
+ ( Derive )
+ }
+}
+
// We directly encode `DefPathHash` because a `LazyValue` would incur a 25% cost.
impl FixedSizeEncoding for Option<DefPathHash> {
type ByteArray = [u8; 16];
[decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>,
[decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
- [] dep_kind: rustc_middle::dep_graph::DepKindStruct,
+ [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>,
]);
)
}
/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
/// jump table instead of large matches.
-pub struct DepKindStruct {
+pub struct DepKindStruct<'tcx> {
/// Anonymous queries cannot be replayed from one compiler invocation to the next.
/// When their result is needed, it is recomputed. They are useful for fine-grained
/// dependency tracking, and caching within one compiler invocation.
/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
/// is actually a `DefPathHash`, and can therefore just look up the corresponding
/// `DefId` in `tcx.def_path_hash_to_def_id`.
- pub force_from_dep_node: Option<fn(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool>,
+ pub force_from_dep_node: Option<fn(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool>,
/// Invoke a query to put the on-disk cached value in memory.
- pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'_>, DepNode)>,
+ pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'tcx>, DepNode)>,
}
impl DepKind {
Some(def_kind)
}
+ /// Finds the id of the parent node to this one.
+ ///
+ /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
pub fn find_parent_node(self, id: HirId) -> Option<HirId> {
if id.local_id == ItemLocalId::from_u32(0) {
Some(self.tcx.hir_owner_parent(id.owner))
Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env)
}
- #[instrument(skip(tcx), level = "debug")]
+ #[instrument(skip(tcx), level = "debug", ret)]
pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let body_id = match tcx.hir().get(hir_id) {
let substs =
ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty })
.substs;
- let uneval_const = tcx.mk_const(ty::ConstS {
+ debug_assert!(!substs.has_free_regions());
+ Self::Ty(tcx.mk_const(ty::ConstS {
kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: ty::WithOptConstParam::unknown(def_id).to_global(),
substs,
promoted: None,
}),
ty,
- });
- debug!(?uneval_const);
- debug_assert!(!uneval_const.has_free_regions());
-
- Self::Ty(uneval_const)
+ }))
}
- #[instrument(skip(tcx), level = "debug")]
+ #[instrument(skip(tcx), level = "debug", ret)]
fn from_opt_const_arg_anon_const(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
Ok(val) => {
- debug!("evaluated const value: {:?}", val);
+ debug!("evaluated const value");
Self::Val(val, ty)
}
Err(_) => {
debug!("error encountered during evaluation");
// Error was handled in `const_eval_resolve`. Here we just create a
// new unevaluated const and error hard later in codegen
- let ty_const = tcx.mk_const(ty::ConstS {
+ Self::Ty(tcx.mk_const(ty::ConstS {
kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: def.to_global(),
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
promoted: None,
}),
ty,
- });
- debug!(?ty_const);
-
- Self::Ty(ty_const)
+ }))
}
}
}
query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxIndexSet<LocalDefId>> {
desc { "testing if a region is late bound" }
}
- /// For a given item (like a struct), gets the default lifetimes to be used
+ /// For a given item's generic parameter, gets the default lifetimes to be used
/// for each parameter if a trait object were to be passed for that parameter.
- /// For example, for `struct Foo<'a, T, U>`, this would be `['static, 'static]`.
- /// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`.
- query object_lifetime_default(key: DefId) -> Option<ObjectLifetimeDefault> {
- desc { "looking up lifetime defaults for generic parameter `{:?}`", key }
+ /// For example, for `T` in `struct Foo<'a, T>`, this would be `'static`.
+ /// For `T` in `struct Foo<'a, T: 'a>`, this would instead be `'a`.
+ /// This query will panic if passed something that is not a type parameter.
+ query object_lifetime_default(key: DefId) -> ObjectLifetimeDefault {
+ desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(key) }
separate_provide_extern
}
query late_bound_vars_map(_: LocalDefId)
/// `let <PAT> = ...`
///
/// If a type annotation is included, it is added as an ascription pattern.
- pattern: Pat<'tcx>,
+ pattern: Box<Pat<'tcx>>,
/// `let pat: ty = <INIT>`
initializer: Option<ExprId>,
},
Let {
expr: ExprId,
- pat: Pat<'tcx>,
+ pat: Box<Pat<'tcx>>,
},
/// A `match` expression.
Match {
/// A `match` arm.
#[derive(Clone, Debug, HashStable)]
pub struct Arm<'tcx> {
- pub pattern: Pat<'tcx>,
+ pub pattern: Box<Pat<'tcx>>,
pub guard: Option<Guard<'tcx>>,
pub body: ExprId,
pub lint_level: LintLevel,
#[derive(Clone, Debug, HashStable)]
pub enum Guard<'tcx> {
If(ExprId),
- IfLet(Pat<'tcx>, ExprId),
+ IfLet(Box<Pat<'tcx>>, ExprId),
}
#[derive(Copy, Clone, Debug, HashStable)]
#[derive(Clone, Debug, HashStable)]
pub struct FieldPat<'tcx> {
pub field: Field,
- pub pattern: Pat<'tcx>,
+ pub pattern: Box<Pat<'tcx>>,
}
#[derive(Clone, Debug, HashStable)]
pub struct Pat<'tcx> {
pub ty: Ty<'tcx>,
pub span: Span,
- pub kind: Box<PatKind<'tcx>>,
+ pub kind: PatKind<'tcx>,
}
impl<'tcx> Pat<'tcx> {
pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
- Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
+ Pat { ty, span: DUMMY_SP, kind: PatKind::Wild }
}
}
AscribeUserType {
ascription: Ascription<'tcx>,
- subpattern: Pat<'tcx>,
+ subpattern: Box<Pat<'tcx>>,
},
/// `x`, `ref x`, `x @ P`, etc.
mode: BindingMode,
var: LocalVarId,
ty: Ty<'tcx>,
- subpattern: Option<Pat<'tcx>>,
+ subpattern: Option<Box<Pat<'tcx>>>,
/// Is this the leftmost occurrence of the binding, i.e., is `var` the
/// `HirId` of this pattern?
is_primary: bool,
/// `box P`, `&P`, `&mut P`, etc.
Deref {
- subpattern: Pat<'tcx>,
+ subpattern: Box<Pat<'tcx>>,
},
/// One of the following:
value: mir::ConstantKind<'tcx>,
},
- Range(PatRange<'tcx>),
+ Range(Box<PatRange<'tcx>>),
/// Matches against a slice, checking the length and extracting elements.
/// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
/// e.g., `&[ref xs @ ..]`.
Slice {
- prefix: Vec<Pat<'tcx>>,
- slice: Option<Pat<'tcx>>,
- suffix: Vec<Pat<'tcx>>,
+ prefix: Box<[Box<Pat<'tcx>>]>,
+ slice: Option<Box<Pat<'tcx>>>,
+ suffix: Box<[Box<Pat<'tcx>>]>,
},
/// Fixed match against an array; irrefutable.
Array {
- prefix: Vec<Pat<'tcx>>,
- slice: Option<Pat<'tcx>>,
- suffix: Vec<Pat<'tcx>>,
+ prefix: Box<[Box<Pat<'tcx>>]>,
+ slice: Option<Box<Pat<'tcx>>>,
+ suffix: Box<[Box<Pat<'tcx>>]>,
},
/// An or-pattern, e.g. `p | q`.
/// Invariant: `pats.len() >= 2`.
Or {
- pats: Vec<Pat<'tcx>>,
+ pats: Box<[Box<Pat<'tcx>>]>,
},
}
-#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+#[derive(Clone, Debug, PartialEq, HashStable)]
pub struct PatRange<'tcx> {
pub lo: mir::ConstantKind<'tcx>,
pub hi: mir::ConstantKind<'tcx>,
};
let mut start_or_comma = || start_or_continue(", ");
- match *self.kind {
+ match self.kind {
PatKind::Wild => write!(f, "_"),
PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
Ok(())
}
PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
- let variant = match *self.kind {
+ let variant = match self.kind {
PatKind::Variant { adt_def, variant_index, .. } => {
Some(adt_def.variant(variant_index))
}
let mut printed = 0;
for p in subpatterns {
- if let PatKind::Wild = *p.pattern.kind {
+ if let PatKind::Wild = p.pattern.kind {
continue;
}
let name = variant.fields[p.field.index()].name;
write!(f, "{}", subpattern)
}
PatKind::Constant { value } => write!(f, "{}", value),
- PatKind::Range(PatRange { lo, hi, end }) => {
+ PatKind::Range(box PatRange { lo, hi, end }) => {
write!(f, "{}", lo)?;
write!(f, "{}", end)?;
write!(f, "{}", hi)
PatKind::Slice { ref prefix, ref slice, ref suffix }
| PatKind::Array { ref prefix, ref slice, ref suffix } => {
write!(f, "[")?;
- for p in prefix {
+ for p in prefix.iter() {
write!(f, "{}{}", start_or_comma(), p)?;
}
if let Some(ref slice) = *slice {
write!(f, "{}", start_or_comma())?;
- match *slice.kind {
+ match slice.kind {
PatKind::Wild => {}
_ => write!(f, "{}", slice)?,
}
write!(f, "..")?;
}
- for p in suffix {
+ for p in suffix.iter() {
write!(f, "{}{}", start_or_comma(), p)?;
}
write!(f, "]")
}
PatKind::Or { ref pats } => {
- for pat in pats {
+ for pat in pats.iter() {
write!(f, "{}{}", start_or_continue(" | "), pat)?;
}
Ok(())
static_assert_size!(Block, 56);
static_assert_size!(Expr<'_>, 64);
static_assert_size!(ExprKind<'_>, 40);
- static_assert_size!(Pat<'_>, 24);
- static_assert_size!(PatKind<'_>, 112);
- static_assert_size!(Stmt<'_>, 72);
- static_assert_size!(StmtKind<'_>, 64);
+ static_assert_size!(Pat<'_>, 72);
+ static_assert_size!(PatKind<'_>, 56);
+ static_assert_size!(Stmt<'_>, 56);
+ static_assert_size!(StmtKind<'_>, 48);
}
pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) {
use PatKind::*;
- match pat.kind.as_ref() {
+ match &pat.kind {
AscribeUserType { subpattern, ascription: _ }
| Deref { subpattern }
| Binding {
Constant { value: _ } => {}
Range(_) => {}
Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
- for subpattern in prefix {
+ for subpattern in prefix.iter() {
visitor.visit_pat(&subpattern);
}
if let Some(pat) = slice {
- visitor.visit_pat(pat);
+ visitor.visit_pat(&pat);
}
- for subpattern in suffix {
+ for subpattern in suffix.iter() {
visitor.visit_pat(&subpattern);
}
}
Or { pats } => {
- for pat in pats {
+ for pat in pats.iter() {
visitor.visit_pat(&pat);
}
}
-use rustc_hir::BindingAnnotation;
-use rustc_hir::BindingAnnotation::*;
-use rustc_hir::Mutability;
+use rustc_hir::{BindingAnnotation, ByRef, Mutability};
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Debug, Copy, HashStable)]
pub enum BindingMode {
TrivialTypeTraversalAndLiftImpls! { BindingMode, }
impl BindingMode {
- pub fn convert(ba: BindingAnnotation) -> BindingMode {
- match ba {
- Unannotated => BindingMode::BindByValue(Mutability::Not),
- Mutable => BindingMode::BindByValue(Mutability::Mut),
- Ref => BindingMode::BindByReference(Mutability::Not),
- RefMut => BindingMode::BindByReference(Mutability::Mut),
+ pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {
+ match by_ref {
+ ByRef::No => BindingMode::BindByValue(mutbl),
+ ByRef::Yes => BindingMode::BindByReference(mutbl),
}
}
}
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> Self {
- debug!("Const::from_anon_const(def={:?})", def);
-
let body_id = match tcx.hir().get_by_def_id(def.did) {
hir::Node::AnonConst(ac) => ac.body,
_ => span_bug!(
pub promoted: P,
}
+impl rustc_errors::IntoDiagnosticArg for Unevaluated<'_> {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ format!("{:?}", self).into_diagnostic_arg()
+ }
+}
+
impl<'tcx> Unevaluated<'tcx> {
#[inline]
pub fn shrink(self) -> Unevaluated<'tcx, ()> {
/// `ValTree` does not have this problem with representation, as it only contains integers or
/// lists of (nested) `ValTree`.
pub enum ValTree<'tcx> {
- /// ZSTs, integers, `bool`, `char` are represented as scalars.
+ /// integers, `bool`, `char` are represented as scalars.
/// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values
/// of these types have the same representation.
Leaf(ScalarInt),
// dont use SliceOrStr for now
/// The fields of any kind of aggregate. Structs, tuples and arrays are represented by
/// listing their fields' values in order.
+ ///
/// Enums are represented by storing their discriminant as a field, followed by all
/// the fields of the variant.
+ ///
+ /// ZST types are represented as an empty slice.
Branch(&'tcx [ValTree<'tcx>]),
}
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
pub struct CanonicalUserTypeAnnotation<'tcx> {
- pub user_ty: CanonicalUserType<'tcx>,
+ pub user_ty: Box<CanonicalUserType<'tcx>>,
pub span: Span,
pub inferred_ty: Ty<'tcx>,
}
pub queries: &'tcx dyn query::QueryEngine<'tcx>,
pub query_caches: query::QueryCaches<'tcx>,
- query_kinds: &'tcx [DepKindStruct],
+ query_kinds: &'tcx [DepKindStruct<'tcx>],
// Internal caches for metadata decoding. No need to track deps on this.
pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
dep_graph: DepGraph,
on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
queries: &'tcx dyn query::QueryEngine<'tcx>,
- query_kinds: &'tcx [DepKindStruct],
+ query_kinds: &'tcx [DepKindStruct<'tcx>],
crate_name: &str,
output_filenames: OutputFilenames,
) -> GlobalCtxt<'tcx> {
}
}
- pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct {
+ pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct<'tcx> {
&self.query_kinds[k as usize]
}
t
}
- #[instrument(skip(self), level = "debug")]
+ #[instrument(skip(self), level = "debug", ret)]
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(debruijn, _) if debruijn < self.current_index => {
Ok(layout)
}
+#[derive(Clone, Copy)]
pub struct LayoutCx<'tcx, C> {
pub tcx: C,
pub param_env: ty::ParamEnv<'tcx>,
)
}
+// Handle safe Rust thin and fat pointers.
+pub fn adjust_for_rust_scalar<'tcx>(
+ cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
+ attrs: &mut ArgAttributes,
+ scalar: Scalar,
+ layout: TyAndLayout<'tcx>,
+ offset: Size,
+ is_return: bool,
+) {
+ // Booleans are always a noundef i1 that needs to be zero-extended.
+ if scalar.is_bool() {
+ attrs.ext(ArgExtension::Zext);
+ attrs.set(ArgAttribute::NoUndef);
+ return;
+ }
+
+ // Scalars which have invalid values cannot be undef.
+ if !scalar.is_always_valid(&cx) {
+ attrs.set(ArgAttribute::NoUndef);
+ }
+
+ // Only pointer types handled below.
+ let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return };
+
+ if !valid_range.contains(0) {
+ attrs.set(ArgAttribute::NonNull);
+ }
+
+ if let Some(pointee) = layout.pointee_info_at(&cx, offset) {
+ if let Some(kind) = pointee.safe {
+ attrs.pointee_align = Some(pointee.align);
+
+ // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
+ // for the entire duration of the function as they can be deallocated
+ // at any time. Same for shared mutable references. If LLVM had a
+ // way to say "dereferenceable on entry" we could use it here.
+ attrs.pointee_size = match kind {
+ PointerKind::UniqueBorrowed
+ | PointerKind::UniqueBorrowedPinned
+ | PointerKind::Frozen => pointee.size,
+ PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
+ };
+
+ // `Box`, `&T`, and `&mut T` cannot be undef.
+ // Note that this only applies to the value of the pointer itself;
+ // this attribute doesn't make it UB for the pointed-to data to be undef.
+ attrs.set(ArgAttribute::NoUndef);
+
+ // The aliasing rules for `Box<T>` are still not decided, but currently we emit
+ // `noalias` for it. This can be turned off using an unstable flag.
+ // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
+ let noalias_for_box = cx.tcx.sess.opts.unstable_opts.box_noalias.unwrap_or(true);
+
+ // `&mut` pointer parameters never alias other parameters,
+ // or mutable global data
+ //
+ // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
+ // and can be marked as both `readonly` and `noalias`, as
+ // LLVM's definition of `noalias` is based solely on memory
+ // dependencies rather than pointer equality
+ //
+ // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
+ // for UniqueBorrowed arguments, so that the codegen backend can decide whether
+ // or not to actually emit the attribute. It can also be controlled with the
+ // `-Zmutable-noalias` debugging option.
+ let no_alias = match kind {
+ PointerKind::SharedMutable
+ | PointerKind::UniqueBorrowed
+ | PointerKind::UniqueBorrowedPinned => false,
+ PointerKind::UniqueOwned => noalias_for_box,
+ PointerKind::Frozen => !is_return,
+ };
+ if no_alias {
+ attrs.set(ArgAttribute::NoAlias);
+ }
+
+ if kind == PointerKind::Frozen && !is_return {
+ attrs.set(ArgAttribute::ReadOnly);
+ }
+
+ if kind == PointerKind::UniqueBorrowed && !is_return {
+ attrs.set(ArgAttribute::NoAliasMutRef);
+ }
+ }
+ }
+}
+
impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
// arguments of this method, into a separate `struct`.
use SpecAbi::*;
let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
- // Handle safe Rust thin and fat pointers.
- let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
- scalar: Scalar,
- layout: TyAndLayout<'tcx>,
- offset: Size,
- is_return: bool| {
- // Booleans are always a noundef i1 that needs to be zero-extended.
- if scalar.is_bool() {
- attrs.ext(ArgExtension::Zext);
- attrs.set(ArgAttribute::NoUndef);
- return;
- }
-
- // Scalars which have invalid values cannot be undef.
- if !scalar.is_always_valid(self) {
- attrs.set(ArgAttribute::NoUndef);
- }
-
- // Only pointer types handled below.
- let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return };
-
- if !valid_range.contains(0) {
- attrs.set(ArgAttribute::NonNull);
- }
-
- if let Some(pointee) = layout.pointee_info_at(self, offset) {
- if let Some(kind) = pointee.safe {
- attrs.pointee_align = Some(pointee.align);
-
- // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
- // for the entire duration of the function as they can be deallocated
- // at any time. Same for shared mutable references. If LLVM had a
- // way to say "dereferenceable on entry" we could use it here.
- attrs.pointee_size = match kind {
- PointerKind::UniqueBorrowed
- | PointerKind::UniqueBorrowedPinned
- | PointerKind::Frozen => pointee.size,
- PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
- };
-
- // `Box`, `&T`, and `&mut T` cannot be undef.
- // Note that this only applies to the value of the pointer itself;
- // this attribute doesn't make it UB for the pointed-to data to be undef.
- attrs.set(ArgAttribute::NoUndef);
-
- // The aliasing rules for `Box<T>` are still not decided, but currently we emit
- // `noalias` for it. This can be turned off using an unstable flag.
- // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
- let noalias_for_box =
- self.tcx().sess.opts.unstable_opts.box_noalias.unwrap_or(true);
-
- // `&mut` pointer parameters never alias other parameters,
- // or mutable global data
- //
- // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
- // and can be marked as both `readonly` and `noalias`, as
- // LLVM's definition of `noalias` is based solely on memory
- // dependencies rather than pointer equality
- //
- // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
- // for UniqueBorrowed arguments, so that the codegen backend can decide whether
- // or not to actually emit the attribute. It can also be controlled with the
- // `-Zmutable-noalias` debugging option.
- let no_alias = match kind {
- PointerKind::SharedMutable
- | PointerKind::UniqueBorrowed
- | PointerKind::UniqueBorrowedPinned => false,
- PointerKind::UniqueOwned => noalias_for_box,
- PointerKind::Frozen => !is_return,
- };
- if no_alias {
- attrs.set(ArgAttribute::NoAlias);
- }
-
- if kind == PointerKind::Frozen && !is_return {
- attrs.set(ArgAttribute::ReadOnly);
- }
-
- if kind == PointerKind::UniqueBorrowed && !is_return {
- attrs.set(ArgAttribute::NoAliasMutRef);
- }
- }
- }
- };
-
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
let is_return = arg_idx.is_none();
let mut arg = ArgAbi::new(self, layout, |layout, scalar, offset| {
let mut attrs = ArgAttributes::new();
- adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return);
+ adjust_for_rust_scalar(*self, &mut attrs, scalar, *layout, offset, is_return);
attrs
});
pub label_res_map: NodeMap<ast::NodeId>,
/// Resolutions for lifetimes.
pub lifetimes_res_map: NodeMap<LifetimeRes>,
- /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
- /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
- /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
- /// field from the original parameter 'a to the new parameter 'a1.
- pub generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
/// Lifetime parameters that lowering will have to introduce.
pub extra_lifetime_params_map: NodeMap<Vec<(Ident, ast::NodeId, LifetimeRes)>>,
}
pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> {
- self.get_attrs(did, attr).next()
+ if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
+ bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr);
+ } else {
+ self.get_attrs(did, attr).next()
+ }
}
/// Determines whether an item is annotated with an attribute.
}
impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
- #[instrument(skip(self), level = "debug")]
fn normalize_generic_arg_after_erasing_regions(
&self,
arg: ty::GenericArg<'tcx>,
) -> ty::GenericArg<'tcx> {
let arg = self.param_env.and(arg);
- debug!(?arg);
self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!(
"Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead",
crate::middle::exported_symbols::SymbolExportInfo,
crate::middle::resolve_lifetime::ObjectLifetimeDefault,
crate::mir::ConstQualifs,
+ ty::AssocItemContainer,
ty::Generics,
ty::ImplPolarity,
ty::ReprOptions,
}
}
+impl rustc_errors::IntoDiagnosticArg for PolyTraitRef<'_> {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ self.to_string().into_diagnostic_arg()
+ }
+}
+
/// An existential reference to a trait, where `Self` is erased.
/// For example, the trait object `Trait<'a, 'b, X, Y>` is:
/// ```ignore (illustrative)
}
// Query provider for `incoherent_impls`.
-#[instrument(level = "debug", skip(tcx))]
pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
let mut impls = Vec::new();
}
/// Expands the given impl trait type, stopping if the type is recursive.
- #[instrument(skip(self), level = "debug")]
+ #[instrument(skip(self), level = "debug", ret)]
pub fn try_expand_impl_trait_type(
self,
def_id: DefId,
};
let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap();
- trace!(?expanded_type);
if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
}
self.has_vars_bound_at_or_above(ty::INNERMOST)
}
- #[instrument(level = "trace")]
+ #[instrument(level = "trace", ret)]
fn has_type_flags(&self, flags: TypeFlags) -> bool {
self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
}
type BreakTy = FoundFlags;
#[inline]
- #[instrument(skip(self), level = "trace")]
+ #[instrument(skip(self), level = "trace", ret)]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = t.flags();
trace!(t.flags=?t.flags());
}
#[inline]
- #[instrument(skip(self), level = "trace")]
+ #[instrument(skip(self), level = "trace", ret)]
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = r.type_flags();
trace!(r.flags=?flags);
}
#[inline]
- #[instrument(level = "trace")]
+ #[instrument(level = "trace", ret)]
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = FlagComputation::for_const(c);
trace!(r.flags=?flags);
}
#[inline]
- #[instrument(level = "trace")]
+ #[instrument(level = "trace", ret)]
fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = FlagComputation::for_unevaluated_const(uv);
trace!(r.flags=?flags);
}
#[inline]
- #[instrument(level = "trace")]
+ #[instrument(level = "trace", ret)]
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!(
"HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
lint_level,
else_block,
} => {
- let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
+ let ignores_expr_result = matches!(pattern.kind, PatKind::Wild);
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
// Enter the remainder scope, i.e., the bindings' destruction scope.
ArmHasGuard(false),
Some((None, initializer_span)),
);
- this.expr_into_pattern(block, pattern.clone(), init) // irrefutable pattern
+ this.expr_into_pattern(block, pattern, init) // irrefutable pattern
}
})
},
Constant { span, user_ty: None, literal }
}
ExprKind::NonHirLiteral { lit, ref user_ty } => {
- let user_ty = user_ty.as_ref().map(|box user_ty| {
+ let user_ty = user_ty.as_ref().map(|user_ty| {
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span,
- user_ty: *user_ty,
+ user_ty: user_ty.clone(),
inferred_ty: ty,
})
});
Constant { span, user_ty: user_ty, literal }
}
ExprKind::ZstLiteral { ref user_ty } => {
- let user_ty = user_ty.as_ref().map(|box user_ty| {
+ let user_ty = user_ty.as_ref().map(|user_ty| {
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span,
- user_ty: *user_ty,
+ user_ty: user_ty.clone(),
inferred_ty: ty,
})
});
Constant { span, user_ty: user_ty, literal }
}
ExprKind::NamedConst { def_id, substs, ref user_ty } => {
- let user_ty = user_ty.as_ref().map(|box user_ty| {
+ let user_ty = user_ty.as_ref().map(|user_ty| {
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span,
- user_ty: *user_ty,
+ user_ty: user_ty.clone(),
inferred_ty: ty,
})
});
fake_borrow_temps,
)
);
- if let Some(box user_ty) = user_ty {
+ if let Some(user_ty) = user_ty {
let annotation_index =
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span: source_info.span,
- user_ty: *user_ty,
+ user_ty: user_ty.clone(),
inferred_ty: expr.ty,
});
let source = &this.thir[source];
let temp =
unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
- if let Some(box user_ty) = user_ty {
+ if let Some(user_ty) = user_ty {
let annotation_index =
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span: source_info.span,
- user_ty: *user_ty,
+ user_ty: user_ty.clone(),
inferred_ty: expr.ty,
});
this.cfg.push(
};
let inferred_ty = expr.ty;
- let user_ty = user_ty.as_ref().map(|box user_ty| {
+ let user_ty = user_ty.as_ref().map(|user_ty| {
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span: source_info.span,
- user_ty: *user_ty,
+ user_ty: user_ty.clone(),
inferred_ty,
})
});
///
/// * From each pre-binding block to the next pre-binding block.
/// * From each otherwise block to the next pre-binding block.
- #[tracing::instrument(level = "debug", skip(self, arms))]
+ #[instrument(level = "debug", skip(self, arms))]
pub(crate) fn match_expr(
&mut self,
destination: Place<'tcx>,
pub(super) fn expr_into_pattern(
&mut self,
mut block: BasicBlock,
- irrefutable_pat: Pat<'tcx>,
+ irrefutable_pat: &Pat<'tcx>,
initializer: &Expr<'tcx>,
) -> BlockAnd<()> {
- match *irrefutable_pat.kind {
+ match irrefutable_pat.kind {
// Optimize the case of `let x = ...` to write directly into `x`
PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
let place =
// broken.
PatKind::AscribeUserType {
subpattern:
- Pat {
+ box Pat {
kind:
- box PatKind::Binding {
- mode: BindingMode::ByValue,
- var,
- subpattern: None,
- ..
+ PatKind::Binding {
+ mode: BindingMode::ByValue, var, subpattern: None, ..
},
..
},
- ascription: thir::Ascription { annotation, variance: _ },
+ ascription: thir::Ascription { ref annotation, variance: _ },
} => {
let place =
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
let ty_source_info = self.source_info(annotation.span);
- let base = self.canonical_user_type_annotations.push(annotation);
+ let base = self.canonical_user_type_annotations.push(annotation.clone());
self.cfg.push(
block,
Statement {
pub(crate) fn place_into_pattern(
&mut self,
block: BasicBlock,
- irrefutable_pat: Pat<'tcx>,
+ irrefutable_pat: &Pat<'tcx>,
initializer: PlaceBuilder<'tcx>,
set_match_place: bool,
) -> BlockAnd<()> {
"visit_primary_bindings: pattern={:?} pattern_user_ty={:?}",
pattern, pattern_user_ty
);
- match *pattern.kind {
+ match pattern.kind {
PatKind::Binding {
mutability,
name,
| PatKind::Slice { ref prefix, ref slice, ref suffix } => {
let from = u64::try_from(prefix.len()).unwrap();
let to = u64::try_from(suffix.len()).unwrap();
- for subpattern in prefix {
+ for subpattern in prefix.iter() {
self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
}
for subpattern in slice {
f,
);
}
- for subpattern in suffix {
+ for subpattern in suffix.iter() {
self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
}
}
// may not all be in the leftmost subpattern. For example in
// `let (x | y) = ...`, the primary binding of `y` occurs in
// the right subpattern
- for subpattern in pats {
+ for subpattern in pats.iter() {
self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f);
}
}
},
/// Test whether the value falls within an inclusive or exclusive range
- Range(PatRange<'tcx>),
+ Range(Box<PatRange<'tcx>>),
/// Test that the length of the slice is equal to `len`.
Len { len: u64, op: BinOp },
// All of the or-patterns have been sorted to the end, so if the first
// pattern is an or-pattern we only have or-patterns.
- match *first_candidate.match_pairs[0].pattern.kind {
+ match first_candidate.match_pairs[0].pattern.kind {
PatKind::Or { .. } => (),
_ => {
self.test_candidates(
let mut otherwise = None;
for match_pair in match_pairs {
- let PatKind::Or { ref pats } = &*match_pair.pattern.kind else {
+ let PatKind::Or { ref pats } = &match_pair.pattern.kind else {
bug!("Or-patterns should have been sorted to the end");
};
let or_span = match_pair.pattern.span;
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
otherwise: &mut Option<BasicBlock>,
- pats: &'pat [Pat<'tcx>],
+ pats: &'pat [Box<Pat<'tcx>>],
or_span: Span,
place: PlaceBuilder<'tcx>,
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
let else_block_span = self.thir[else_block].span;
let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| {
let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
- let pat = Pat { ty: init.ty, span: else_block_span, kind: Box::new(PatKind::Wild) };
+ let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild };
let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
this.declare_bindings(
visibility_scope,
loop {
let match_pairs = mem::take(&mut candidate.match_pairs);
- if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, place }] =
+ if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] =
&*match_pairs
{
existing_bindings.extend_from_slice(&new_bindings);
// late as possible.
candidate
.match_pairs
- .sort_by_key(|pair| matches!(*pair.pattern.kind, PatKind::Or { .. }));
+ .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. }));
debug!(simplified = ?candidate, "simplify_candidate");
return false; // if we were not able to simplify any, done.
}
&mut self,
candidate: &Candidate<'pat, 'tcx>,
place: PlaceBuilder<'tcx>,
- pats: &'pat [Pat<'tcx>],
+ pats: &'pat [Box<Pat<'tcx>>],
) -> Vec<Candidate<'pat, 'tcx>> {
pats.iter()
- .map(|pat| {
+ .map(|box pat| {
let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard);
self.simplify_candidate(&mut candidate);
candidate
candidate: &mut Candidate<'pat, 'tcx>,
) -> Result<(), MatchPair<'pat, 'tcx>> {
let tcx = self.tcx;
- match *match_pair.pattern.kind {
+ match match_pair.pattern.kind {
PatKind::AscribeUserType {
ref subpattern,
ascription: thir::Ascription { ref annotation, variance },
Err(match_pair)
}
- PatKind::Range(PatRange { lo, hi, end }) => {
+ PatKind::Range(box PatRange { lo, hi, end }) => {
let (range, bias) = match *lo.ty().kind() {
ty::Char => {
(Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
&mut candidate.match_pairs,
&match_pair.place,
prefix,
- slice.as_ref(),
+ slice,
suffix,
);
Ok(())
&mut candidate.match_pairs,
&match_pair.place,
prefix,
- slice.as_ref(),
+ slice,
suffix,
);
Ok(())
///
/// It is a bug to call this with a not-fully-simplified pattern.
pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
- match *match_pair.pattern.kind {
+ match match_pair.pattern.kind {
PatKind::Variant { adt_def, substs: _, variant_index: _, subpatterns: _ } => Test {
span: match_pair.pattern.span,
kind: TestKind::Switch {
kind: TestKind::Eq { value, ty: match_pair.pattern.ty },
},
- PatKind::Range(range) => {
+ PatKind::Range(ref range) => {
assert_eq!(range.lo.ty(), match_pair.pattern.ty);
assert_eq!(range.hi.ty(), match_pair.pattern.ty);
- Test { span: match_pair.pattern.span, kind: TestKind::Range(range) }
+ Test { span: match_pair.pattern.span, kind: TestKind::Range(range.clone()) }
}
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
return false;
};
- match *match_pair.pattern.kind {
+ match match_pair.pattern.kind {
PatKind::Constant { value } => {
options
.entry(value)
PatKind::Variant { .. } => {
panic!("you should have called add_variants_to_switch instead!");
}
- PatKind::Range(range) => {
+ PatKind::Range(ref range) => {
// Check that none of the switch values are in the range.
- self.values_not_contained_in_range(range, options).unwrap_or(false)
+ self.values_not_contained_in_range(&*range, options).unwrap_or(false)
}
PatKind::Slice { .. }
| PatKind::Array { .. }
return false;
};
- match *match_pair.pattern.kind {
+ match match_pair.pattern.kind {
PatKind::Variant { adt_def: _, variant_index, .. } => {
// We have a pattern testing for variant `variant_index`
// set the corresponding index to true
}
}
- TestKind::Range(PatRange { lo, hi, ref end }) => {
+ TestKind::Range(box PatRange { lo, hi, ref end }) => {
let lower_bound_success = self.cfg.start_new_block();
let target_blocks = make_target_blocks(self);
let (match_pair_index, match_pair) =
candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?;
- match (&test.kind, &*match_pair.pattern.kind) {
+ match (&test.kind, &match_pair.pattern.kind) {
// If we are performing a variant switch, then this
// informs variant patterns, but nothing else.
(
Some(index)
}
- (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(range)) => {
+ (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(ref range)) => {
let not_contained =
- self.values_not_contained_in_range(range, options).unwrap_or(false);
+ self.values_not_contained_in_range(&*range, options).unwrap_or(false);
if not_contained {
// No switch values are contained in the pattern range,
match_pair_index,
candidate,
prefix,
- slice.as_ref(),
+ slice,
suffix,
);
Some(0)
match_pair_index,
candidate,
prefix,
- slice.as_ref(),
+ slice,
suffix,
);
Some(0)
}
}
- (&TestKind::Range(test), &PatKind::Range(pat)) => {
+ (&TestKind::Range(ref test), &PatKind::Range(ref pat)) => {
use std::cmp::Ordering::*;
if test == pat {
no_overlap
}
- (&TestKind::Range(range), &PatKind::Constant { value }) => {
- if let Some(false) = self.const_range_contains(range, value) {
+ (&TestKind::Range(ref range), &PatKind::Constant { value }) => {
+ if let Some(false) = self.const_range_contains(&*range, value) {
// `value` is not contained in the testing range,
// so `value` can be matched only if this test fails.
Some(1)
// However, at this point we can still encounter or-patterns that were extracted
// from previous calls to `sort_candidate`, so we need to manually address that
// case to avoid panicking in `self.test()`.
- if let PatKind::Or { .. } = &*match_pair.pattern.kind {
+ if let PatKind::Or { .. } = &match_pair.pattern.kind {
return None;
}
&mut self,
match_pair_index: usize,
candidate: &mut Candidate<'pat, 'tcx>,
- prefix: &'pat [Pat<'tcx>],
- opt_slice: Option<&'pat Pat<'tcx>>,
- suffix: &'pat [Pat<'tcx>],
+ prefix: &'pat [Box<Pat<'tcx>>],
+ opt_slice: &'pat Option<Box<Pat<'tcx>>>,
+ suffix: &'pat [Box<Pat<'tcx>>],
) {
let removed_place = candidate.match_pairs.remove(match_pair_index).place;
self.prefix_slice_suffix(
fn const_range_contains(
&self,
- range: PatRange<'tcx>,
+ range: &PatRange<'tcx>,
value: ConstantKind<'tcx>,
) -> Option<bool> {
use std::cmp::Ordering::*;
fn values_not_contained_in_range(
&self,
- range: PatRange<'tcx>,
+ range: &PatRange<'tcx>,
options: &FxIndexMap<ConstantKind<'tcx>, u128>,
) -> Option<bool> {
for &val in options.keys() {
&mut self,
match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>,
place: &PlaceBuilder<'tcx>,
- prefix: &'pat [Pat<'tcx>],
- opt_slice: Option<&'pat Pat<'tcx>>,
- suffix: &'pat [Pat<'tcx>],
+ prefix: &'pat [Box<Pat<'tcx>>],
+ opt_slice: &'pat Option<Box<Pat<'tcx>>>,
+ suffix: &'pat [Box<Pat<'tcx>>],
) {
let tcx = self.tcx;
let (min_length, exact_size) = if let Ok(place_resolved) =
let original_source_scope = self.source_scope;
let span = pattern.span;
self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
- match *pattern.kind {
+ match pattern.kind {
// Don't introduce extra copies for simple bindings
PatKind::Binding {
mutability,
Some((Some(&place), span)),
);
let place_builder = PlaceBuilder::from(local);
- unpack!(block = self.place_into_pattern(block, pattern, place_builder, false));
+ unpack!(
+ block =
+ self.place_into_pattern(block, pattern.as_ref(), place_builder, false)
+ );
}
}
self.source_scope = original_source_scope;
fn visit_pat(&mut self, pat: &Pat<'tcx>) {
if self.in_union_destructure {
- match *pat.kind {
+ match pat.kind {
// binding to a variable allows getting stuff out of variable
PatKind::Binding { .. }
// match is conditional on having this value
}
};
- match &*pat.kind {
+ match &pat.kind {
PatKind::Leaf { .. } => {
if let ty::Adt(adt_def, ..) = pat.ty.kind() {
if adt_def.is_union() {
{
debug!("mirror_stmts: user_ty={:?}", user_ty);
let annotation = CanonicalUserTypeAnnotation {
- user_ty,
+ user_ty: Box::new(user_ty),
span: ty.span,
inferred_ty: self.typeck_results.node_type(ty.hir_id),
};
- pattern = Pat {
+ pattern = Box::new(Pat {
ty: pattern.ty,
span: pattern.span,
- kind: Box::new(PatKind::AscribeUserType {
+ kind: PatKind::AscribeUserType {
ascription: Ascription {
annotation,
variance: ty::Variance::Covariant,
},
subpattern: pattern,
- }),
- };
+ },
+ });
}
}
let kind = match expr.kind {
// Here comes the interesting stuff:
- hir::ExprKind::MethodCall(segment, ref args, fn_span) => {
+ hir::ExprKind::MethodCall(segment, receiver, ref args, fn_span) => {
// Rewrite a.b(c) into UFCS form like Trait::b(a, c)
let expr = self.method_callee(expr, segment.ident.span, None);
// When we apply adjustments to the receiver, use the span of
// the overall method call for better diagnostics. args[0]
// is guaranteed to exist, since a method call always has a receiver.
- let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span));
- tracing::info!("Using method span: {:?}", expr.span);
- let args = self.mirror_exprs(args);
+ let old_adjustment_span =
+ self.adjustment_span.replace((receiver.hir_id, expr_span));
+ info!("Using method span: {:?}", expr.span);
+ let args = std::iter::once(receiver)
+ .chain(args.iter())
+ .map(|expr| self.mirror_expr(expr))
+ .collect();
self.adjustment_span = old_adjustment_span;
ExprKind::Call {
ty: expr.ty,
}
}
- #[tracing::instrument(level = "debug", skip(self))]
- pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
+ #[instrument(level = "debug", skip(self))]
+ pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Box<Pat<'tcx>> {
let p = match self.tcx.hir().get(p.hir_id) {
Node::Pat(p) => p,
node => bug!("pattern became {:?}", node),
/// Converts an evaluated constant to a pattern (if possible).
/// This means aggregate values (like structs and enums) are converted
/// to a pattern that matches the value (as if you'd compared via structural equality).
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
pub(super) fn const_to_pat(
&self,
cv: mir::ConstantKind<'tcx>,
id: hir::HirId,
span: Span,
mir_structural_match_violation: bool,
- ) -> Pat<'tcx> {
- let pat = self.tcx.infer_ctxt().enter(|infcx| {
+ ) -> Box<Pat<'tcx>> {
+ self.tcx.infer_ctxt().enter(|infcx| {
let mut convert = ConstToPat::new(self, id, span, infcx);
convert.to_pat(cv, mir_structural_match_violation)
- });
-
- debug!(?pat);
- pat
+ })
}
}
&mut self,
cv: mir::ConstantKind<'tcx>,
mir_structural_match_violation: bool,
- ) -> Pat<'tcx> {
+ ) -> Box<Pat<'tcx>> {
trace!(self.treat_byte_string_as_slice);
// This method is just a wrapper handling a validity check; the heavy lifting is
// performed by the recursive `recur` method, which is not meant to be
// level of indirection can be eliminated
let inlined_const_as_pat =
- self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| Pat {
- span: self.span,
- ty: cv.ty(),
- kind: Box::new(PatKind::Constant { value: cv }),
+ self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| {
+ Box::new(Pat {
+ span: self.span,
+ ty: cv.ty(),
+ kind: PatKind::Constant { value: cv },
+ })
});
if self.include_lint_checks && !self.saw_const_match_error.get() {
&self,
cv: mir::ConstantKind<'tcx>,
mir_structural_match_violation: bool,
- ) -> Result<Pat<'tcx>, FallbackToConstRef> {
+ ) -> Result<Box<Pat<'tcx>>, FallbackToConstRef> {
let id = self.id;
let span = self.span;
let tcx = self.tcx();
.map(|val| self.recur(*val, false))
.collect::<Result<_, _>>()?,
slice: None,
- suffix: Vec::new(),
+ suffix: Box::new([]),
},
ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
// These are not allowed and will error elsewhere anyway.
let old = self.behind_reference.replace(true);
let array = tcx.deref_mir_constant(self.param_env.and(cv));
let val = PatKind::Deref {
- subpattern: Pat {
- kind: Box::new(PatKind::Array {
+ subpattern: Box::new(Pat {
+ kind: PatKind::Array {
prefix: tcx
.destructure_mir_constant(param_env, array)
.fields
.map(|val| self.recur(*val, false))
.collect::<Result<_, _>>()?,
slice: None,
- suffix: vec![],
- }),
+ suffix: Box::new([]),
+ },
span,
ty: *pointee_ty,
- },
+ }),
};
self.behind_reference.set(old);
val
let old = self.behind_reference.replace(true);
let array = tcx.deref_mir_constant(self.param_env.and(cv));
let val = PatKind::Deref {
- subpattern: Pat {
- kind: Box::new(PatKind::Slice {
+ subpattern: Box::new(Pat {
+ kind: PatKind::Slice {
prefix: tcx
.destructure_mir_constant(param_env, array)
.fields
.map(|val| self.recur(*val, false))
.collect::<Result<_, _>>()?,
slice: None,
- suffix: vec![],
- }),
+ suffix: Box::new([]),
+ },
span,
ty: tcx.mk_slice(elem_ty),
- },
+ }),
};
self.behind_reference.set(old);
val
);
}
- Ok(Pat { span, ty: cv.ty(), kind: Box::new(kind) })
+ Ok(Box::new(Pat { span, ty: cv.ty(), kind }))
}
}
/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
- if let PatKind::Or { pats } = pat.kind.as_ref() {
- for pat in pats {
- expand(pat, vec);
+ if let PatKind::Or { pats } = &pat.kind {
+ for pat in pats.iter() {
+ expand(&pat, vec);
}
} else {
vec.push(pat)
let kind = if lo == hi {
PatKind::Constant { value: lo_const }
} else {
- PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included })
+ PatKind::Range(Box::new(PatRange {
+ lo: lo_const,
+ hi: hi_const,
+ end: RangeEnd::Included,
+ }))
};
- Pat { ty, span: DUMMY_SP, kind: Box::new(kind) }
+ Pat { ty, span: DUMMY_SP, kind }
}
/// Lint on likely incorrect range patterns (#63987)
let mkpat = |pat| DeconstructedPat::from_pat(cx, pat);
let ctor;
let fields;
- match pat.kind.as_ref() {
+ match &pat.kind {
PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern),
PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat),
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
fields = Fields::singleton(cx, pat);
}
ty::Adt(adt, _) => {
- ctor = match pat.kind.as_ref() {
+ ctor = match pat.kind {
PatKind::Leaf { .. } => Single,
- PatKind::Variant { variant_index, .. } => Variant(*variant_index),
+ PatKind::Variant { variant_index, .. } => Variant(variant_index),
_ => bug!(),
};
let variant = &adt.variant(ctor.variant_index_for_adt(*adt));
}
}
}
- &PatKind::Range(PatRange { lo, hi, end }) => {
+ &PatKind::Range(box PatRange { lo, hi, end }) => {
let ty = lo.ty();
ctor = if let Some(int_range) = IntRange::from_range(
cx.tcx,
FixedLen(prefix.len() + suffix.len())
};
ctor = Slice(Slice::new(array_len, kind));
- fields = Fields::from_iter(cx, prefix.iter().chain(suffix).map(mkpat));
+ fields =
+ Fields::from_iter(cx, prefix.iter().chain(suffix.iter()).map(|p| mkpat(&*p)));
}
PatKind::Or { .. } => {
ctor = Or;
pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> {
let is_wildcard = |pat: &Pat<'_>| {
- matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
+ matches!(pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
};
- let mut subpatterns = self.iter_fields().map(|p| p.to_pat(cx));
- let pat = match &self.ctor {
+ let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx)));
+ let kind = match &self.ctor {
Single | Variant(_) => match self.ty.kind() {
ty::Tuple(..) => PatKind::Leaf {
subpatterns: subpatterns
.enumerate()
- .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
+ .map(|(i, pattern)| FieldPat { field: Field::new(i), pattern })
.collect(),
},
ty::Adt(adt_def, _) if adt_def.is_box() => {
FixedLen(_) => PatKind::Slice {
prefix: subpatterns.collect(),
slice: None,
- suffix: vec![],
+ suffix: Box::new([]),
},
VarLen(prefix, _) => {
let mut subpatterns = subpatterns.peekable();
subpatterns.next();
}
}
- let suffix: Vec<_> = subpatterns.collect();
+ let suffix: Box<[_]> = subpatterns.collect();
let wild = Pat::wildcard_from_ty(self.ty);
- PatKind::Slice { prefix, slice: Some(wild), suffix }
+ PatKind::Slice {
+ prefix: prefix.into_boxed_slice(),
+ slice: Some(Box::new(wild)),
+ suffix,
+ }
}
}
}
&Str(value) => PatKind::Constant { value },
- &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
+ &FloatRange(lo, hi, end) => PatKind::Range(Box::new(PatRange { lo, hi, end })),
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
Wildcard | NonExhaustive => PatKind::Wild,
Missing { .. } => bug!(
}
};
- Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(pat) }
+ Pat { ty: self.ty, span: DUMMY_SP, kind }
}
pub(super) fn is_or_pat(&self) -> bool {
param_env: ty::ParamEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
pat: &'tcx hir::Pat<'tcx>,
-) -> Pat<'tcx> {
+) -> Box<Pat<'tcx>> {
let mut pcx = PatCtxt::new(tcx, param_env, typeck_results);
let result = pcx.lower_pattern(pat);
if !pcx.errors.is_empty() {
self
}
- pub(crate) fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
+ pub(crate) fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
// When implicit dereferences have been inserted in this pattern, the unadjusted lowered
// pattern has the type that results *after* dereferencing. For example, in this code:
//
let unadjusted_pat = self.lower_pattern_unadjusted(pat);
self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
unadjusted_pat,
- |pat, ref_ty| {
+ |pat: Box<_>, ref_ty| {
debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
- Pat {
+ Box::new(Pat {
span: pat.span,
ty: *ref_ty,
- kind: Box::new(PatKind::Deref { subpattern: pat }),
- }
+ kind: PatKind::Deref { subpattern: pat },
+ })
},
)
}
expr: &'tcx hir::Expr<'tcx>,
) -> (PatKind<'tcx>, Option<Ascription<'tcx>>) {
match self.lower_lit(expr) {
- PatKind::AscribeUserType { ascription, subpattern: Pat { kind: box kind, .. } } => {
+ PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
(kind, Some(ascription))
}
kind => (kind, None),
match (end, cmp) {
// `x..y` where `x < y`.
// Non-empty because the range includes at least `x`.
- (RangeEnd::Excluded, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
+ (RangeEnd::Excluded, Some(Ordering::Less)) => {
+ PatKind::Range(Box::new(PatRange { lo, hi, end }))
+ }
// `x..y` where `x >= y`. The range is empty => error.
(RangeEnd::Excluded, _) => {
struct_span_err!(
// `x..=y` where `x == y`.
(RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo },
// `x..=y` where `x < y`.
- (RangeEnd::Included, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
+ (RangeEnd::Included, Some(Ordering::Less)) => {
+ PatKind::Range(Box::new(PatRange { lo, hi, end }))
+ }
// `x..=y` where `x > y` hence the range is empty => error.
(RangeEnd::Included, _) => {
let mut err = struct_span_err!(
}
}
- fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
+ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
let mut ty = self.typeck_results.node_type(pat.hir_id);
let kind = match pat.kind {
// constants somewhere. Have them on the range pattern.
for end in &[lo, hi] {
if let Some((_, Some(ascription))) = end {
- let subpattern = Pat { span: pat.span, ty, kind: Box::new(kind) };
+ let subpattern = Box::new(Pat { span: pat.span, ty, kind });
kind =
PatKind::AscribeUserType { ascription: ascription.clone(), subpattern };
}
hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
};
- Pat { span: pat.span, ty, kind: Box::new(kind) }
+ Box::new(Pat { span: pat.span, ty, kind })
}
fn lower_tuple_subpats(
.collect()
}
- fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Vec<Pat<'tcx>> {
+ fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Box<Pat<'tcx>>]> {
pats.iter().map(|p| self.lower_pattern(p)).collect()
}
- fn lower_opt_pattern(&mut self, pat: &'tcx Option<&'tcx hir::Pat<'tcx>>) -> Option<Pat<'tcx>> {
+ fn lower_opt_pattern(
+ &mut self,
+ pat: &'tcx Option<&'tcx hir::Pat<'tcx>>,
+ ) -> Option<Box<Pat<'tcx>>> {
pat.as_ref().map(|p| self.lower_pattern(p))
}
if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
let annotation = CanonicalUserTypeAnnotation {
- user_ty,
+ user_ty: Box::new(user_ty),
span,
inferred_ty: self.typeck_results.node_type(hir_id),
};
kind = PatKind::AscribeUserType {
- subpattern: Pat { span, ty, kind: Box::new(kind) },
+ subpattern: Box::new(Pat { span, ty, kind }),
ascription: Ascription { annotation, variance: ty::Variance::Covariant },
};
}
/// it to `const_to_pat`. Any other path (like enum variants without fields)
/// is converted to the corresponding pattern via `lower_variant_or_leaf`.
#[instrument(skip(self), level = "debug")]
- fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Pat<'tcx> {
+ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box<Pat<'tcx>> {
let ty = self.typeck_results.node_type(id);
let res = self.typeck_results.qpath_res(qpath, id);
- let pat_from_kind = |kind| Pat { span, ty, kind: Box::new(kind) };
+ let pat_from_kind = |kind| Box::new(Pat { span, ty, kind });
let (def_id, is_associated_const) = match res {
Res::Def(DefKind::Const, def_id) => (def_id, false),
let user_provided_types = self.typeck_results().user_provided_types();
if let Some(&user_ty) = user_provided_types.get(id) {
let annotation = CanonicalUserTypeAnnotation {
- user_ty,
+ user_ty: Box::new(user_ty),
span,
inferred_ty: self.typeck_results().node_type(id),
};
- Pat {
+ Box::new(Pat {
span,
- kind: Box::new(PatKind::AscribeUserType {
+ kind: PatKind::AscribeUserType {
subpattern: pattern,
ascription: Ascription {
annotation,
/// `variance` field documentation for details.
variance: ty::Variance::Contravariant,
},
- }),
+ },
ty: const_.ty(),
- }
+ })
} else {
pattern
}
_ => bug!("Expected either ConstKind::Param or ConstKind::Unevaluated"),
}
}
- mir::ConstantKind::Val(_, _) => *self.const_to_pat(value, id, span, false).kind,
+ mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind,
}
}
fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
let (lit, neg) = match expr.kind {
hir::ExprKind::Path(ref qpath) => {
- return *self.lower_path(qpath, expr.hir_id, expr.span).kind;
+ return self.lower_path(qpath, expr.hir_id, expr.span).kind;
}
hir::ExprKind::ConstBlock(ref anon_const) => {
return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
let lit_input =
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) {
- Ok(constant) => *self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
+ Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
Err(LitToConstError::Reported) => PatKind::Wild,
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
}
}
}
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<[T]> {
+ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+ self.iter().map(|t| t.fold_with(folder)).collect()
+ }
+}
+
impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
self.as_ref().map(|t| t.fold_with(folder))
PatKind::Deref { subpattern: subpattern.fold_with(folder) }
}
PatKind::Constant { value } => PatKind::Constant { value },
- PatKind::Range(range) => PatKind::Range(range),
+ PatKind::Range(ref range) => PatKind::Range(range.clone()),
PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice {
prefix: prefix.fold_with(folder),
slice: slice.fold_with(folder),
/// `is_under_guard` is used to inform if the pattern has a guard. If it
/// has one it must not be inserted into the matrix. This shouldn't be
/// relied on for soundness.
-#[instrument(level = "debug", skip(cx, matrix, hir_id))]
+#[instrument(level = "debug", skip(cx, matrix, hir_id), ret)]
fn is_useful<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
v.head().set_reachable();
}
- debug!(?ret);
ret
}
#![feature(trusted_step)]
#![feature(try_blocks)]
#![feature(yeet_expr)]
+#![feature(if_let_guard)]
#![recursion_limit = "256"]
#[macro_use]
use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::Visitor as _;
use rustc_middle::mir::{
- traversal, AnalysisPhase, Body, ConstQualifs, MirPass, MirPhase, Promoted, RuntimePhase,
+ traversal, AnalysisPhase, Body, ConstQualifs, Constant, LocalDecl, MirPass, MirPhase, Operand,
+ Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind,
+ TerminatorKind,
};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
+use rustc_span::sym;
#[macro_use]
mod pass_manager;
};
}
+fn remap_mir_for_const_eval_select<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ mut body: Body<'tcx>,
+ context: hir::Constness,
+) -> Body<'tcx> {
+ for bb in body.basic_blocks.as_mut().iter_mut() {
+ let terminator = bb.terminator.as_mut().expect("invalid terminator");
+ match terminator.kind {
+ TerminatorKind::Call {
+ func: Operand::Constant(box Constant { ref literal, .. }),
+ ref mut args,
+ destination,
+ target,
+ cleanup,
+ fn_span,
+ ..
+ } if let ty::FnDef(def_id, _) = *literal.ty().kind()
+ && tcx.item_name(def_id) == sym::const_eval_select
+ && tcx.is_intrinsic(def_id) =>
+ {
+ let [tupled_args, called_in_const, called_at_rt]: [_; 3] = std::mem::take(args).try_into().unwrap();
+ let ty = tupled_args.ty(&body.local_decls, tcx);
+ let fields = ty.tuple_fields();
+ let num_args = fields.len();
+ let func = if context == hir::Constness::Const { called_in_const } else { called_at_rt };
+ let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) = match tupled_args {
+ Operand::Constant(_) => {
+ // there is no good way of extracting a tuple arg from a constant (const generic stuff)
+ // so we just create a temporary and deconstruct that.
+ let local = body.local_decls.push(LocalDecl::new(ty, fn_span));
+ bb.statements.push(Statement {
+ source_info: SourceInfo::outermost(fn_span),
+ kind: StatementKind::Assign(Box::new((local.into(), Rvalue::Use(tupled_args.clone())))),
+ });
+ (Operand::Move, local.into())
+ }
+ Operand::Move(place) => (Operand::Move, place),
+ Operand::Copy(place) => (Operand::Copy, place),
+ };
+ let place_elems = place.projection;
+ let arguments = (0..num_args).map(|x| {
+ let mut place_elems = place_elems.to_vec();
+ place_elems.push(ProjectionElem::Field(x.into(), fields[x]));
+ let projection = tcx.intern_place_elems(&place_elems);
+ let place = Place {
+ local: place.local,
+ projection,
+ };
+ method(place)
+ }).collect();
+ terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, cleanup, from_hir_call: false, fn_span };
+ }
+ _ => {}
+ }
+ }
+ body
+}
+
fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let def_id = def_id.expect_local();
tcx.mir_keys(()).contains(&def_id)
.body_const_context(def.did)
.expect("mir_for_ctfe should not be used for runtime functions");
- let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone();
+ let body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone();
+
+ let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const);
match context {
// Do not const prop functions, either they get executed at runtime or exported to metadata,
Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other),
}
debug!("about to call mir_drops_elaborated...");
- let mut body =
+ let body =
tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal();
+ let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst);
debug!("body: {:#?}", body);
run_optimization_passes(tcx, &mut body);
//! method in operand position, we treat it as a neighbor of the current
//! mono item. Calls are just a special case of that.
//!
-//! #### Closures
-//! In a way, closures are a simple case. Since every closure object needs to be
-//! constructed somewhere, we can reliably discover them by observing
-//! `RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also
-//! true for closures inlined from other crates.
-//!
//! #### Drop glue
//! Drop glue mono items are introduced by MIR drop-statements. The
//! generated mono item will again have drop-glue item neighbors if the
// We've been here already, no need to search again.
return;
}
- debug!("BEGIN collect_items_rec({})", starting_point.node);
let mut neighbors = MonoItems { compute_inlining: true, tcx, items: Vec::new() };
let recursion_depth_reset;
if let Some((def_id, depth)) = recursion_depth_reset {
recursion_depths.insert(def_id, depth);
}
-
- debug!("END collect_items_rec({})", starting_point.node);
}
/// Format instance name that is already known to be too long for rustc.
mir::TerminatorKind::Call { ref func, .. } => {
let callee_ty = func.ty(self.body, tcx);
let callee_ty = self.monomorphize(callee_ty);
- visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output);
+ visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output)
}
mir::TerminatorKind::Drop { ref place, .. }
| mir::TerminatorKind::DropAndReplace { ref place, .. } => {
}
}
-#[instrument(skip(tcx), level = "debug")]
+#[instrument(skip(tcx), level = "debug", ret)]
fn create_fn_mono_item<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
source: Span,
) -> Spanned<MonoItem<'tcx>> {
- debug!("create_fn_mono_item(instance={})", instance);
-
let def_id = instance.def_id();
if tcx.sess.opts.unstable_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id) {
crate::util::dump_closure_profile(tcx, instance);
}
- let respanned = respan(source, MonoItem::Fn(instance.polymorphize(tcx)));
- debug!(?respanned);
-
- respanned
+ respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
}
/// Creates a `MonoItem` for each method that is referenced by the vtable for
#[instrument(skip(self), level = "debug")]
fn push_if_root(&mut self, def_id: LocalDefId) {
if self.is_root(def_id) {
- debug!("RootCollector::push_if_root: found root def_id={:?}", def_id);
+ debug!("found root");
let instance = Instance::mono(self.tcx, def_id.to_def_id());
self.output.push(create_fn_mono_item(self.tcx, instance, DUMMY_SP));
/// the return type of `main`. This is not needed when
/// the user writes their own `start` manually.
fn push_extra_entry_roots(&mut self) {
- let Some((main_def_id, EntryFnType::Main)) = self.entry_fn else {
+ let Some((main_def_id, EntryFnType::Main { .. })) = self.entry_fn else {
return;
};
///
/// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all
/// parameters are used).
-#[instrument(level = "debug", skip(tcx))]
fn unused_generic_params<'tcx>(
tcx: TyCtxt<'tcx>,
instance: ty::InstanceDef<'tcx>,
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{edition::Edition, BytePos, Pos, Span};
-use tracing::debug;
-
mod tokentrees;
mod unescape_error_reporting;
mod unicode_chars;
range: Range<usize>,
error: EscapeError,
) {
- tracing::debug!(
+ debug!(
"emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}",
- lit,
- span_with_quotes,
- mode,
- range,
- error
+ lit, span_with_quotes, mode, range, error
);
let last_char = || {
let c = lit[range.clone()].chars().rev().next().unwrap();
use rustc_span::{sym, BytePos, Span};
use std::convert::TryInto;
-use tracing::debug;
-
// Public for rustfmt usage
#[derive(Debug)]
pub enum InnerAttrPolicy<'a> {
// Prepend `self.attrs` to `attrs`.
// FIXME: require passing an NT to prevent misuse of this method
pub(crate) fn prepend_to_nt_inner(self, attrs: &mut AttrVec) {
- let mut self_attrs = self.attrs.clone();
+ let mut self_attrs = self.attrs;
std::mem::swap(attrs, &mut self_attrs);
attrs.extend(self_attrs);
}
use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind};
use rustc_ast::util::parser::AssocOp;
use rustc_ast::{
- AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
- BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Mutability, Param, Pat,
- PatKind, Path, PathSegment, QSelf, Ty, TyKind,
+ AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingAnnotation, Block,
+ BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind,
+ Path, PathSegment, QSelf, Ty, TyKind,
};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use std::mem::take;
use crate::parser;
-use tracing::{debug, trace};
const TURBOFISH_SUGGESTION_STR: &str =
"use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments";
pub(super) fn dummy_arg(ident: Ident) -> Param {
let pat = P(Pat {
id: ast::DUMMY_NODE_ID,
- kind: PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None),
+ kind: PatKind::Ident(BindingAnnotation::NONE, ident, None),
span: ident.span,
tokens: None,
});
}
_ => {}
},
- PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => {
+ PatKind::Ident(BindingAnnotation::NONE, ident, None) => {
match &first_pat.kind {
PatKind::Ident(_, old_ident, _) => {
let path = PatKind::Path(
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID};
use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
-use rustc_ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind};
+use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind};
use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData};
use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
use rustc_ast::{MacArgs, MacCall, MacDelimiter};
use std::convert::TryFrom;
use std::mem;
-use tracing::debug;
impl<'a> Parser<'a> {
/// Parses a source module as a crate. This is the main entry point for the parser.
match ty {
Ok(ty) => {
let ident = Ident::new(kw::Empty, this.prev_token.span);
- let bm = BindingMode::ByValue(Mutability::Not);
+ let bm = BindingAnnotation::NONE;
let pat = this.mk_pat_ident(ty.span, bm, ident);
(pat, ty)
}
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{Span, DUMMY_SP};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use tracing::debug;
use std::ops::Range;
use std::{cmp, mem, slice};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter};
use rustc_ast::{
- self as ast, AttrVec, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat, PatField, PatKind,
- Path, QSelf, RangeEnd, RangeSyntax,
+ self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat,
+ PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
} else if self.eat_keyword(kw::Ref) {
// Parse ref ident @ pat / ref mut ident @ pat
let mutbl = self.parse_mutability();
- self.parse_pat_ident(BindingMode::ByRef(mutbl))?
+ self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl))?
} else if self.eat_keyword(kw::Box) {
self.parse_pat_box()?
} else if self.check_inline_const(0) {
// Parse `ident @ pat`
// This can give false positives and parse nullary enums,
// they are dealt with later in resolve.
- self.parse_pat_ident(BindingMode::ByValue(Mutability::Not))?
+ self.parse_pat_ident(BindingAnnotation::NONE)?
} else if self.is_start_of_pat_with_path() {
// Parse pattern starting with a path
let (qself, path) = if self.eat_lt() {
let mut pat = self.parse_pat_no_top_alt(Some("identifier"))?;
// If we don't have `mut $ident (@ pat)?`, error.
- if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind {
+ if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind
+ {
// Don't recurse into the subpattern.
// `mut` on the outer binding doesn't affect the inner bindings.
*m = Mutability::Mut;
)
.emit();
- self.parse_pat_ident(BindingMode::ByRef(Mutability::Mut))
+ self.parse_pat_ident(BindingAnnotation::REF_MUT)
}
/// Turn all by-value immutable bindings in a pattern into mutable bindings.
struct AddMut(bool);
impl MutVisitor for AddMut {
fn visit_pat(&mut self, pat: &mut P<Pat>) {
- if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind
+ if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) =
+ &mut pat.kind
{
self.0 = true;
*m = Mutability::Mut;
/// Parses `ident` or `ident @ pat`.
/// Used by the copy foo and ref foo patterns to give a good
/// error message when parsing mistakes like `ref foo(a, b)`.
- fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> {
+ fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<'a, PatKind> {
let ident = self.parse_ident()?;
let sub = if self.eat(&token::At) {
Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
.struct_span_err(self.prev_token.span, "expected identifier, found enum pattern"));
}
- Ok(PatKind::Ident(binding_mode, ident, sub))
+ Ok(PatKind::Ident(binding_annotation, ident, sub))
}
/// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
None
};
- Ok(PatKind::Ident(
- BindingMode::ByValue(Mutability::Not),
- Ident::new(kw::Box, box_span),
- sub,
- ))
+ Ok(PatKind::Ident(BindingAnnotation::NONE, Ident::new(kw::Box, box_span), sub))
} else {
let pat = self.parse_pat_with_range_pat(false, None)?;
self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span));
let fieldname = self.parse_field_name()?;
hi = self.prev_token.span;
- let bind_type = match (is_ref, is_mut) {
- (true, true) => BindingMode::ByRef(Mutability::Mut),
- (true, false) => BindingMode::ByRef(Mutability::Not),
- (false, true) => BindingMode::ByValue(Mutability::Mut),
- (false, false) => BindingMode::ByValue(Mutability::Not),
+ let mutability = match is_mut {
+ false => Mutability::Not,
+ true => Mutability::Mut,
};
-
- let fieldpat = self.mk_pat_ident(boxed_span.to(hi), bind_type, fieldname);
+ let ann = BindingAnnotation(ByRef::from(is_ref), mutability);
+ let fieldpat = self.mk_pat_ident(boxed_span.to(hi), ann, fieldname);
let subpat =
if is_box { self.mk_pat(lo.to(hi), PatKind::Box(fieldpat)) } else { fieldpat };
(subpat, fieldname, true)
})
}
- pub(super) fn mk_pat_ident(&self, span: Span, bm: BindingMode, ident: Ident) -> P<Pat> {
- self.mk_pat(span, PatKind::Ident(bm, ident, None))
+ pub(super) fn mk_pat_ident(&self, span: Span, ann: BindingAnnotation, ident: Ident) -> P<Pat> {
+ self.mk_pat(span, PatKind::Ident(ann, ident, None))
}
pub(super) fn mk_pat(&self, span: Span, kind: PatKind) -> P<Pat> {
use rustc_span::symbol::{kw, sym, Ident};
use std::mem;
-use tracing::debug;
/// Specifies how to parse a path.
#[derive(Copy, Clone, PartialEq)]
sym::no_implicit_prelude => {
self.check_generic_attr(hir_id, attr, target, &[Target::Mod])
}
- sym::rustc_object_lifetime_default => {
- self.check_object_lifetime_default(hir_id, span)
- }
+ sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id),
_ => {}
}
}
/// Debugging aid for `object_lifetime_default` query.
- fn check_object_lifetime_default(&self, hir_id: HirId, span: Span) {
+ fn check_object_lifetime_default(&self, hir_id: HirId) {
let tcx = self.tcx;
if let Some(generics) = tcx.hir().get_generics(tcx.hir().local_def_id(hir_id)) {
- let object_lifetime_default_reprs: String = generics
- .params
- .iter()
- .filter_map(|p| {
- let param_id = tcx.hir().local_def_id(p.hir_id);
- let default = tcx.object_lifetime_default(param_id)?;
- Some(match default {
- ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(),
- ObjectLifetimeDefault::Static => "'static".to_owned(),
- ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
- ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
- })
- })
- .collect::<Vec<String>>()
- .join(",");
-
- tcx.sess.span_err(span, &object_lifetime_default_reprs);
+ for p in generics.params {
+ let hir::GenericParamKind::Type { .. } = p.kind else { continue };
+ let param_id = tcx.hir().local_def_id(p.hir_id);
+ let default = tcx.object_lifetime_default(param_id);
+ let repr = match default {
+ ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(),
+ ObjectLifetimeDefault::Static => "'static".to_owned(),
+ ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
+ ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
+ };
+ tcx.sess.span_err(p.span, &repr);
+ }
}
}
sym::automatically_derived,
sym::start,
sym::rustc_main,
+ sym::unix_sigpipe,
sym::derive,
sym::test,
sym::test_case,
-use rustc_ast::{entry::EntryPointType, Attribute};
+use rustc_ast::entry::EntryPointType;
use rustc_errors::struct_span_err;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{DefIdTree, TyCtxt};
-use rustc_session::config::{CrateType, EntryFnType};
+use rustc_session::config::{sigpipe, CrateType, EntryFnType};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol, DUMMY_SP};
}
}
-fn err_if_attr_found(ctxt: &EntryContext<'_>, attrs: &[Attribute], sym: Symbol) {
+fn err_if_attr_found(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol, details: &str) {
+ let attrs = ctxt.tcx.hir().attrs(id.hir_id());
if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym) {
ctxt.tcx
.sess
- .struct_span_err(
- attr.span,
- &format!("`{}` attribute can only be used on functions", sym),
- )
+ .struct_span_err(attr.span, &format!("`{}` attribute {}", sym, details))
.emit();
}
}
let at_root = ctxt.tcx.opt_local_parent(id.def_id) == Some(CRATE_DEF_ID);
match entry_point_type(ctxt, id, at_root) {
- EntryPointType::None => (),
+ EntryPointType::None => {
+ err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`");
+ }
_ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
- let attrs = ctxt.tcx.hir().attrs(id.hir_id());
- err_if_attr_found(ctxt, attrs, sym::start);
- err_if_attr_found(ctxt, attrs, sym::rustc_main);
+ err_if_attr_found(ctxt, id, sym::start, "can only be used on functions");
+ err_if_attr_found(ctxt, id, sym::rustc_main, "can only be used on functions");
}
EntryPointType::MainNamed => (),
EntryPointType::OtherMain => {
+ err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on root `fn main()`");
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
}
EntryPointType::RustcMainAttr => {
}
}
EntryPointType::Start => {
+ err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`");
if ctxt.start_fn.is_none() {
ctxt.start_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
} else {
fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
if let Some((def_id, _)) = visitor.start_fn {
Some((def_id.to_def_id(), EntryFnType::Start))
- } else if let Some((def_id, _)) = visitor.attr_main_fn {
- Some((def_id.to_def_id(), EntryFnType::Main))
+ } else if let Some((local_def_id, _)) = visitor.attr_main_fn {
+ let def_id = local_def_id.to_def_id();
+ Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) }))
} else {
if let Some(main_def) = tcx.resolutions(()).main_def && let Some(def_id) = main_def.opt_fn_def_id() {
// non-local main imports are handled below
)
.emit();
}
- return Some((def_id, EntryFnType::Main));
+ return Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) }));
}
no_main_err(tcx, visitor);
None
}
}
+fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
+ if let Some(attr) = tcx.get_attr(def_id, sym::unix_sigpipe) {
+ match (attr.value_str(), attr.meta_item_list()) {
+ (Some(sym::inherit), None) => sigpipe::INHERIT,
+ (Some(sym::sig_ign), None) => sigpipe::SIG_IGN,
+ (Some(sym::sig_dfl), None) => sigpipe::SIG_DFL,
+ (_, Some(_)) => {
+ // Keep going so that `fn emit_malformed_attribute()` can print
+ // an excellent error message
+ sigpipe::DEFAULT
+ }
+ _ => {
+ tcx.sess
+ .struct_span_err(
+ attr.span,
+ "valid values for `#[unix_sigpipe = \"...\"]` are `inherit`, `sig_ign`, or `sig_dfl`",
+ )
+ .emit();
+ sigpipe::DEFAULT
+ }
+ }
+ } else {
+ sigpipe::DEFAULT
+ }
+}
+
fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
let sp = tcx.def_span(CRATE_DEF_ID);
if *tcx.sess.parse_sess.reached_eof.borrow() {
};
tcx.hir().walk_toplevel_module(&mut collector);
tcx.hir().walk_attributes(&mut collector);
- collector.print("HIR STATS");
+ collector.print("HIR STATS", "hir-stats");
}
-pub fn print_ast_stats(krate: &ast::Crate, title: &str) {
+pub fn print_ast_stats(krate: &ast::Crate, title: &str, prefix: &str) {
use rustc_ast::visit::Visitor;
let mut collector =
StatCollector { krate: None, nodes: FxHashMap::default(), seen: FxHashSet::default() };
collector.visit_crate(krate);
- collector.print(title);
+ collector.print(title, prefix);
}
impl<'k> StatCollector<'k> {
}
}
- fn print(&self, title: &str) {
+ fn print(&self, title: &str, prefix: &str) {
let mut nodes: Vec<_> = self.nodes.iter().collect();
nodes.sort_by_key(|&(_, ref node)| node.stats.count * node.stats.size);
let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum();
- eprintln!("\n{}\n", title);
-
- eprintln!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
- eprintln!("----------------------------------------------------------------");
+ eprintln!("{} {}", prefix, title);
+ eprintln!(
+ "{} {:<18}{:>18}{:>14}{:>14}",
+ prefix, "Name", "Accumulated Size", "Count", "Item Size"
+ );
+ eprintln!("{} ----------------------------------------------------------------", prefix);
let percent = |m, n| (m * 100) as f64 / n as f64;
for (label, node) in nodes {
let size = node.stats.count * node.stats.size;
eprintln!(
- "{:<18}{:>10} ({:4.1}%){:>14}{:>14}",
+ "{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}",
+ prefix,
label,
to_readable_str(size),
percent(size, total_size),
for (label, subnode) in subnodes {
let size = subnode.count * subnode.size;
eprintln!(
- "- {:<18}{:>10} ({:4.1}%){:>14}",
+ "{} - {:<18}{:>10} ({:4.1}%){:>14}",
+ prefix,
label,
to_readable_str(size),
percent(size, total_size),
}
}
}
- eprintln!("----------------------------------------------------------------");
- eprintln!("{:<18}{:>10}\n", "Total", to_readable_str(total_size));
+ eprintln!("{} ----------------------------------------------------------------", prefix);
+ eprintln!("{} {:<18}{:>10}", prefix, "Total", to_readable_str(total_size));
+ eprintln!("{}", prefix);
}
}
+// Used to avoid boilerplate for types with many variants.
+macro_rules! record_variants {
+ (
+ ($self:ident, $val:expr, $kind:expr, $id:expr, $mod:ident, $ty:ty, $tykind:ident),
+ [$($variant:ident),*]
+ ) => {
+ match $kind {
+ $(
+ $mod::$tykind::$variant { .. } => {
+ $self.record_variant(stringify!($ty), stringify!($variant), $id, $val)
+ }
+ )*
+ }
+ };
+}
+
impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
fn visit_param(&mut self, param: &'v hir::Param<'v>) {
self.record("Param", Id::Node(param.hir_id), param);
}
fn visit_item(&mut self, i: &'v hir::Item<'v>) {
- self.record("Item", Id::Node(i.hir_id()), i);
+ record_variants!(
+ (self, i, i.kind, Id::Node(i.hir_id()), hir, Item, ItemKind),
+ [
+ ExternCrate,
+ Use,
+ Static,
+ Const,
+ Fn,
+ Macro,
+ Mod,
+ ForeignMod,
+ GlobalAsm,
+ TyAlias,
+ OpaqueTy,
+ Enum,
+ Struct,
+ Union,
+ Trait,
+ TraitAlias,
+ Impl
+ ]
+ );
hir_visit::walk_item(self, i)
}
+ fn visit_body(&mut self, b: &'v hir::Body<'v>) {
+ self.record("Body", Id::None, b);
+ hir_visit::walk_body(self, b);
+ }
+
+ fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: HirId) {
+ self.record("Mod", Id::None, m);
+ hir_visit::walk_mod(self, m, n)
+ }
+
fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) {
- self.record("ForeignItem", Id::Node(i.hir_id()), i);
+ record_variants!(
+ (self, i, i.kind, Id::Node(i.hir_id()), hir, ForeignItem, ForeignItemKind),
+ [Fn, Static, Type]
+ );
hir_visit::walk_foreign_item(self, i)
}
}
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
- self.record("Stmt", Id::Node(s.hir_id), s);
+ record_variants!(
+ (self, s, s.kind, Id::Node(s.hir_id), hir, Stmt, StmtKind),
+ [Local, Item, Expr, Semi]
+ );
hir_visit::walk_stmt(self, s)
}
}
fn visit_pat(&mut self, p: &'v hir::Pat<'v>) {
- self.record("Pat", Id::Node(p.hir_id), p);
+ record_variants!(
+ (self, p, p.kind, Id::Node(p.hir_id), hir, Pat, PatKind),
+ [Wild, Binding, Struct, TupleStruct, Or, Path, Tuple, Box, Ref, Lit, Range, Slice]
+ );
hir_visit::walk_pat(self, p)
}
- fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
- self.record("Expr", Id::Node(ex.hir_id), ex);
- hir_visit::walk_expr(self, ex)
+ fn visit_pat_field(&mut self, f: &'v hir::PatField<'v>) {
+ self.record("PatField", Id::Node(f.hir_id), f);
+ hir_visit::walk_pat_field(self, f)
+ }
+
+ fn visit_expr(&mut self, e: &'v hir::Expr<'v>) {
+ record_variants!(
+ (self, e, e.kind, Id::Node(e.hir_id), hir, Expr, ExprKind),
+ [
+ Box, ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type,
+ DropTemps, Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index,
+ Path, AddrOf, Break, Continue, Ret, InlineAsm, Struct, Repeat, Yield, Err
+ ]
+ );
+ hir_visit::walk_expr(self, e)
+ }
+
+ fn visit_let_expr(&mut self, lex: &'v hir::Let<'v>) {
+ self.record("Let", Id::Node(lex.hir_id), lex);
+ hir_visit::walk_let_expr(self, lex)
+ }
+
+ fn visit_expr_field(&mut self, f: &'v hir::ExprField<'v>) {
+ self.record("ExprField", Id::Node(f.hir_id), f);
+ hir_visit::walk_expr_field(self, f)
}
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
- self.record("Ty", Id::Node(t.hir_id), t);
+ record_variants!(
+ (self, t, t.kind, Id::Node(t.hir_id), hir, Ty, TyKind),
+ [
+ Slice,
+ Array,
+ Ptr,
+ Rptr,
+ BareFn,
+ Never,
+ Tup,
+ Path,
+ OpaqueDef,
+ TraitObject,
+ Typeof,
+ Infer,
+ Err
+ ]
+ );
hir_visit::walk_ty(self, t)
}
+ fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
+ self.record("GenericParam", Id::Node(p.hir_id), p);
+ hir_visit::walk_generic_param(self, p)
+ }
+
+ fn visit_generics(&mut self, g: &'v hir::Generics<'v>) {
+ self.record("Generics", Id::None, g);
+ hir_visit::walk_generics(self, g)
+ }
+
+ fn visit_where_predicate(&mut self, p: &'v hir::WherePredicate<'v>) {
+ record_variants!(
+ (self, p, p, Id::None, hir, WherePredicate, WherePredicate),
+ [BoundPredicate, RegionPredicate, EqPredicate]
+ );
+ hir_visit::walk_where_predicate(self, p)
+ }
+
fn visit_fn(
&mut self,
fk: hir_visit::FnKind<'v>,
hir_visit::walk_fn(self, fk, fd, b, s, id)
}
- fn visit_where_predicate(&mut self, predicate: &'v hir::WherePredicate<'v>) {
- self.record("WherePredicate", Id::None, predicate);
- hir_visit::walk_where_predicate(self, predicate)
+ fn visit_use(&mut self, p: &'v hir::Path<'v>, hir_id: hir::HirId) {
+ // This is `visit_use`, but the type is `Path` so record it that way.
+ self.record("Path", Id::None, p);
+ hir_visit::walk_use(self, p, hir_id)
}
fn visit_trait_item(&mut self, ti: &'v hir::TraitItem<'v>) {
- self.record("TraitItem", Id::Node(ti.hir_id()), ti);
+ record_variants!(
+ (self, ti, ti.kind, Id::Node(ti.hir_id()), hir, TraitItem, TraitItemKind),
+ [Const, Fn, Type]
+ );
hir_visit::walk_trait_item(self, ti)
}
+ fn visit_trait_item_ref(&mut self, ti: &'v hir::TraitItemRef) {
+ self.record("TraitItemRef", Id::Node(ti.id.hir_id()), ti);
+ hir_visit::walk_trait_item_ref(self, ti)
+ }
+
fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) {
- self.record("ImplItem", Id::Node(ii.hir_id()), ii);
+ record_variants!(
+ (self, ii, ii.kind, Id::Node(ii.hir_id()), hir, ImplItem, ImplItemKind),
+ [Const, Fn, TyAlias]
+ );
hir_visit::walk_impl_item(self, ii)
}
- fn visit_param_bound(&mut self, bounds: &'v hir::GenericBound<'v>) {
- self.record("GenericBound", Id::None, bounds);
- hir_visit::walk_param_bound(self, bounds)
+ fn visit_foreign_item_ref(&mut self, fi: &'v hir::ForeignItemRef) {
+ self.record("ForeignItemRef", Id::Node(fi.id.hir_id()), fi);
+ hir_visit::walk_foreign_item_ref(self, fi)
+ }
+
+ fn visit_impl_item_ref(&mut self, ii: &'v hir::ImplItemRef) {
+ self.record("ImplItemRef", Id::Node(ii.id.hir_id()), ii);
+ hir_visit::walk_impl_item_ref(self, ii)
+ }
+
+ fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) {
+ record_variants!(
+ (self, b, b, Id::None, hir, GenericBound, GenericBound),
+ [Trait, LangItemTrait, Outlives]
+ );
+ hir_visit::walk_param_bound(self, b)
}
fn visit_field_def(&mut self, s: &'v hir::FieldDef<'v>) {
hir_visit::walk_variant(self, v)
}
- fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
- self.record("Lifetime", Id::Node(lifetime.hir_id), lifetime);
- hir_visit::walk_lifetime(self, lifetime)
- }
-
- fn visit_qpath(&mut self, qpath: &'v hir::QPath<'v>, id: hir::HirId, span: Span) {
- self.record("QPath", Id::None, qpath);
- hir_visit::walk_qpath(self, qpath, id, span)
+ fn visit_generic_arg(&mut self, ga: &'v hir::GenericArg<'v>) {
+ record_variants!(
+ (self, ga, ga, Id::Node(ga.hir_id()), hir, GenericArg, GenericArg),
+ [Lifetime, Type, Const, Infer]
+ );
+ match ga {
+ hir::GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
+ hir::GenericArg::Type(ty) => self.visit_ty(ty),
+ hir::GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
+ hir::GenericArg::Infer(inf) => self.visit_infer(inf),
+ }
}
fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
hir_visit::walk_path(self, path)
}
- // `PathSegment` has one inline use (in `ast::ExprKind::MethodCall`) and
- // one non-inline use (in `Path::segments`). The latter case is more common
- // than the former case, so we implement this visitor and tolerate the
- // double counting in the former case.
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v hir::PathSegment<'v>) {
self.record("PathSegment", Id::None, path_segment);
hir_visit::walk_path_segment(self, path_span, path_segment)
}
+ fn visit_generic_args(&mut self, sp: Span, ga: &'v hir::GenericArgs<'v>) {
+ self.record("GenericArgs", Id::None, ga);
+ hir_visit::walk_generic_args(self, sp, ga)
+ }
+
fn visit_assoc_type_binding(&mut self, type_binding: &'v hir::TypeBinding<'v>) {
self.record("TypeBinding", Id::Node(type_binding.hir_id), type_binding);
hir_visit::walk_assoc_type_binding(self, type_binding)
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
self.record("Attribute", Id::Attr(attr.id), attr);
}
-}
-// Used to avoid boilerplate for types with many variants.
-macro_rules! record_variants {
- (
- ($self:ident, $val:expr, $kind:expr, $ty:ty, $tykind:ident), // mandatory pieces
- [$($variant:ident),*]
- ) => {
- match $kind {
- $(
- ast::$tykind::$variant { .. } => {
- $self.record_variant(stringify!($ty), stringify!($variant), Id::None, $val)
- }
- )*
- }
- };
+ fn visit_inline_asm(&mut self, asm: &'v hir::InlineAsm<'v>, id: HirId) {
+ self.record("InlineAsm", Id::None, asm);
+ hir_visit::walk_inline_asm(self, asm, id);
+ }
}
impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
record_variants!(
- (self, i, i.kind, ForeignItem, ForeignItemKind),
+ (self, i, i.kind, Id::None, ast, ForeignItem, ForeignItemKind),
[Static, Fn, TyAlias, MacCall]
);
ast_visit::walk_foreign_item(self, i)
fn visit_item(&mut self, i: &'v ast::Item) {
record_variants!(
- (self, i, i.kind, Item, ItemKind),
+ (self, i, i.kind, Id::None, ast, Item, ItemKind),
[
ExternCrate,
Use,
fn visit_stmt(&mut self, s: &'v ast::Stmt) {
record_variants!(
- (self, s, s.kind, Stmt, StmtKind),
+ (self, s, s.kind, Id::None, ast, Stmt, StmtKind),
[Local, Item, Expr, Semi, Empty, MacCall]
);
ast_visit::walk_stmt(self, s)
fn visit_pat(&mut self, p: &'v ast::Pat) {
record_variants!(
- (self, p, p.kind, Pat, PatKind),
+ (self, p, p.kind, Id::None, ast, Pat, PatKind),
[
Wild,
Ident,
fn visit_expr(&mut self, e: &'v ast::Expr) {
record_variants!(
- (self, e, e.kind, Expr, ExprKind),
+ (self, e, e.kind, Id::None, ast, Expr, ExprKind),
[
Box, Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign,
fn visit_ty(&mut self, t: &'v ast::Ty) {
record_variants!(
- (self, t, t.kind, Ty, TyKind),
+ (self, t, t.kind, Id::None, ast, Ty, TyKind),
[
Slice,
Array,
fn visit_where_predicate(&mut self, p: &'v ast::WherePredicate) {
record_variants!(
- (self, p, p, WherePredicate, WherePredicate),
+ (self, p, p, Id::None, ast, WherePredicate, WherePredicate),
[BoundPredicate, RegionPredicate, EqPredicate]
);
ast_visit::walk_where_predicate(self, p)
fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
record_variants!(
- (self, i, i.kind, AssocItem, AssocItemKind),
+ (self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind),
[Const, Fn, TyAlias, MacCall]
);
ast_visit::walk_assoc_item(self, i, ctxt);
}
fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) {
- record_variants!((self, b, b, GenericBound, GenericBound), [Trait, Outlives]);
+ record_variants!(
+ (self, b, b, Id::None, ast, GenericBound, GenericBound),
+ [Trait, Outlives]
+ );
ast_visit::walk_param_bound(self, b)
}
// common, so we don't implement `visit_use_tree` and tolerate the missed
// coverage in the latter case.
+ // `PathSegment` has one inline use (in `ast::ExprKind::MethodCall`) and
+ // one non-inline use (in `ast::Path::segments`). The latter case is more
+ // common than the former case, so we implement this visitor and tolerate
+ // the double counting in the former case.
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v ast::PathSegment) {
self.record("PathSegment", Id::None, path_segment);
ast_visit::walk_path_segment(self, path_span, path_segment)
// common, so we implement `visit_generic_args` and tolerate the double
// counting in the former case.
fn visit_generic_args(&mut self, sp: Span, g: &'v ast::GenericArgs) {
- record_variants!((self, g, g, GenericArgs, GenericArgs), [AngleBracketed, Parenthesized]);
+ record_variants!(
+ (self, g, g, Id::None, ast, GenericArgs, GenericArgs),
+ [AngleBracketed, Parenthesized]
+ );
ast_visit::walk_generic_args(self, sp, g)
}
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
- record_variants!((self, attr, attr.kind, Attribute, AttrKind), [Normal, DocComment]);
+ record_variants!(
+ (self, attr, attr.kind, Id::None, ast, Attribute, AttrKind),
+ [Normal, DocComment]
+ );
ast_visit::walk_attribute(self, attr)
}
//! collect them instead.
use rustc_ast::{Attribute, MetaItemKind};
+use rustc_attr::VERSION_PLACEHOLDER;
use rustc_errors::struct_span_err;
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
}
}
}
- const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
let version = option_env!("CFG_VERSION").unwrap_or("<current>");
self.propagate_through_expr(&f, succ)
}
- hir::ExprKind::MethodCall(.., ref args, _) => {
+ hir::ExprKind::MethodCall(.., receiver, ref args, _) => {
let succ = self.check_is_ty_uninhabited(expr, succ);
- self.propagate_through_exprs(args, succ)
+ let succ = self.propagate_through_exprs(args, succ);
+ self.propagate_through_expr(receiver, succ)
}
hir::ExprKind::Tup(ref exprs) => self.propagate_through_exprs(exprs, succ),
}
}
- #[tracing::instrument(skip(self), level = "INFO")]
+ #[instrument(skip(self), level = "INFO")]
fn report_unused(
&self,
hir_ids_and_spans: Vec<(HirId, Span, Span)>,
for param in params {
match param.pat.kind {
hir::PatKind::Wild
- | hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, _, None) => {}
+ | hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {}
_ => {
tcx.sess
.struct_span_err(
// added, such as `core::intrinsics::transmute`
let parents = path.segments.iter().rev().skip(1);
for path_segment in parents {
- if let Some(def_id) = path_segment.res.as_ref().and_then(Res::opt_def_id) {
+ if let Some(def_id) = path_segment.res.opt_def_id() {
// use `None` for id to prevent deprecation check
self.tcx.check_stability_allow_unstable(
def_id,
pub vis_span: Span,
}
+#[derive(SessionDiagnostic)]
+#[diag(privacy::report_access_level)]
+pub struct ReportAccessLevel {
+ #[primary_span]
+ pub span: Span,
+ pub descr: String,
+}
+
#[derive(LintDiagnostic)]
#[diag(privacy::from_private_dep_in_public_interface)]
pub struct FromPrivateDependencyInPublicInterface<'a> {
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
+#[macro_use]
+extern crate tracing;
+
mod errors;
use rustc_ast::MacroDef;
use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
use rustc_session::lint;
use rustc_span::hygiene::Transparency;
-use rustc_span::symbol::{kw, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
use std::marker::PhantomData;
use errors::{
FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
- InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, UnnamedItemIsPrivate,
+ InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, ReportAccessLevel,
+ UnnamedItemIsPrivate,
};
////////////////////////////////////////////////////////////////////////////////
}
}
+////////////////////////////////////////////////////////////////////////////////
+/// Visitor, used for AccessLevels table checking
+////////////////////////////////////////////////////////////////////////////////
+pub struct TestReachabilityVisitor<'tcx, 'a> {
+ tcx: TyCtxt<'tcx>,
+ access_levels: &'a AccessLevels,
+}
+
+impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
+ fn access_level_diagnostic(&mut self, def_id: LocalDefId) {
+ if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_access_level) {
+ let access_level = format!("{:?}", self.access_levels.map.get(&def_id));
+ let span = self.tcx.def_span(def_id.to_def_id());
+ self.tcx.sess.emit_err(ReportAccessLevel { span, descr: access_level });
+ }
+ }
+}
+
+impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> {
+ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
+ self.access_level_diagnostic(item.def_id);
+
+ match item.kind {
+ hir::ItemKind::Enum(ref def, _) => {
+ for variant in def.variants.iter() {
+ let variant_id = self.tcx.hir().local_def_id(variant.id);
+ self.access_level_diagnostic(variant_id);
+ for field in variant.data.fields() {
+ let def_id = self.tcx.hir().local_def_id(field.hir_id);
+ self.access_level_diagnostic(def_id);
+ }
+ }
+ }
+ hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
+ for field in def.fields() {
+ let def_id = self.tcx.hir().local_def_id(field.hir_id);
+ self.access_level_diagnostic(def_id);
+ }
+ }
+ _ => {}
+ }
+ }
+
+ fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) {
+ self.access_level_diagnostic(item.def_id);
+ }
+ fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) {
+ self.access_level_diagnostic(item.def_id);
+ }
+ fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
+ self.access_level_diagnostic(item.def_id);
+ }
+}
+
//////////////////////////////////////////////////////////////////////////////////////
/// Name privacy visitor, checks privacy and reports violations.
/// Most of name privacy checks are performed during the main resolution phase,
fn leaks_private_dep(&self, item_id: DefId) -> bool {
let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate);
- tracing::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
+ debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
ret
}
}
}
}
+ let mut check_visitor = TestReachabilityVisitor { tcx, access_levels: &visitor.access_levels };
+ tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor);
+
tcx.arena.alloc(visitor.access_levels)
}
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lock;
use rustc_errors::{Diagnostic, Handler};
-use rustc_middle::dep_graph::{self, DepKind, DepNodeIndex, SerializedDepNodeIndex};
+use rustc_middle::dep_graph::{
+ self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex,
+};
use rustc_middle::ty::tls::{self, ImplicitCtxt};
use rustc_middle::ty::{self, TyCtxt};
-use rustc_query_system::dep_graph::HasDepContext;
+use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext};
use rustc_query_system::ich::StableHashingContext;
use rustc_query_system::query::{
- QueryContext, QueryJobId, QueryMap, QuerySideEffects, QueryStackFrame,
+ force_query, QueryConfig, QueryContext, QueryDescription, QueryJobId, QueryMap,
+ QuerySideEffects, QueryStackFrame,
};
use std::any::Any;
use std::num::NonZeroU64;
QueryStackFrame::new(name, description, span, def_kind, hash)
}
+fn try_load_from_on_disk_cache<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode)
+where
+ Q: QueryDescription<QueryCtxt<'tcx>>,
+ Q::Key: DepNodeParams<TyCtxt<'tcx>>,
+{
+ debug_assert!(tcx.dep_graph.is_green(&dep_node));
+
+ let key = Q::Key::recover(tcx, &dep_node).unwrap_or_else(|| {
+ panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)
+ });
+ if Q::cache_on_disk(tcx, &key) {
+ let _ = Q::execute_query(tcx, key);
+ }
+}
+
+fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool
+where
+ Q: QueryDescription<QueryCtxt<'tcx>>,
+ Q::Key: DepNodeParams<TyCtxt<'tcx>>,
+{
+ if let Some(key) = Q::Key::recover(tcx, &dep_node) {
+ #[cfg(debug_assertions)]
+ let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
+ let tcx = QueryCtxt::from_tcx(tcx);
+ force_query::<Q, _>(tcx, key, dep_node);
+ true
+ } else {
+ false
+ }
+}
+
+pub(crate) fn query_callback<'tcx, Q: QueryConfig>(
+ is_anon: bool,
+ is_eval_always: bool,
+) -> DepKindStruct<'tcx>
+where
+ Q: QueryDescription<QueryCtxt<'tcx>>,
+ Q::Key: DepNodeParams<TyCtxt<'tcx>>,
+{
+ let fingerprint_style = Q::Key::fingerprint_style();
+
+ if is_anon || !fingerprint_style.reconstructible() {
+ return DepKindStruct {
+ is_anon,
+ is_eval_always,
+ fingerprint_style,
+ force_from_dep_node: None,
+ try_load_from_on_disk_cache: None,
+ };
+ }
+
+ DepKindStruct {
+ is_anon,
+ is_eval_always,
+ fingerprint_style,
+ force_from_dep_node: Some(force_from_dep_node::<Q>),
+ try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache::<Q>),
+ }
+}
+
// NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros
// invoked by `rustc_query_append`.
macro_rules! define_queries {
input: ($(([$($modifiers)*] [$($attr)*] [$name]))*)
}
- mod make_query {
- use super::*;
-
- // Create an eponymous constructor for each query.
- $(#[allow(nonstandard_style)] $(#[$attr])*
- pub fn $name<'tcx>(tcx: QueryCtxt<'tcx>, key: <queries::$name<'tcx> as QueryConfig>::Key) -> QueryStackFrame {
- let kind = dep_graph::DepKind::$name;
- let name = stringify!($name);
- $crate::plumbing::create_query_frame(tcx, queries::$name::describe, key, kind, name)
- })*
- }
-
#[allow(nonstandard_style)]
mod queries {
use std::marker::PhantomData;
try_load_from_disk: Self::TRY_LOAD_FROM_DISK,
}
}
+
+ fn execute_query(tcx: TyCtxt<'tcx>, k: Self::Key) -> Self::Stored {
+ tcx.$name(k)
+ }
})*
#[allow(nonstandard_style)]
mod query_callbacks {
use super::*;
- use rustc_middle::dep_graph::DepNode;
- use rustc_query_system::dep_graph::DepNodeParams;
- use rustc_query_system::query::{force_query, QueryDescription};
use rustc_query_system::dep_graph::FingerprintStyle;
// We use this for most things when incr. comp. is turned off.
- pub fn Null() -> DepKindStruct {
+ pub fn Null<'tcx>() -> DepKindStruct<'tcx> {
DepKindStruct {
is_anon: false,
is_eval_always: false,
}
// We use this for the forever-red node.
- pub fn Red() -> DepKindStruct {
+ pub fn Red<'tcx>() -> DepKindStruct<'tcx> {
DepKindStruct {
is_anon: false,
is_eval_always: false,
}
}
- pub fn TraitSelect() -> DepKindStruct {
+ pub fn TraitSelect<'tcx>() -> DepKindStruct<'tcx> {
DepKindStruct {
is_anon: true,
is_eval_always: false,
}
}
- pub fn CompileCodegenUnit() -> DepKindStruct {
+ pub fn CompileCodegenUnit<'tcx>() -> DepKindStruct<'tcx> {
DepKindStruct {
is_anon: false,
is_eval_always: false,
}
}
- pub fn CompileMonoItem() -> DepKindStruct {
+ pub fn CompileMonoItem<'tcx>() -> DepKindStruct<'tcx> {
DepKindStruct {
is_anon: false,
is_eval_always: false,
}
}
- $(pub(crate) fn $name()-> DepKindStruct {
- let is_anon = is_anon!([$($modifiers)*]);
- let is_eval_always = is_eval_always!([$($modifiers)*]);
-
- let fingerprint_style =
- <<queries::$name<'_> as QueryConfig>::Key as DepNodeParams<TyCtxt<'_>>>::fingerprint_style();
-
- if is_anon || !fingerprint_style.reconstructible() {
- return DepKindStruct {
- is_anon,
- is_eval_always,
- fingerprint_style,
- force_from_dep_node: None,
- try_load_from_on_disk_cache: None,
- }
- }
-
- #[inline(always)]
- fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> Option<<queries::$name<'tcx> as QueryConfig>::Key> {
- <<queries::$name<'_> as QueryConfig>::Key as DepNodeParams<TyCtxt<'_>>>::recover(tcx, &dep_node)
- }
-
- fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool {
- if let Some(key) = recover(tcx, dep_node) {
- #[cfg(debug_assertions)]
- let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
- let tcx = QueryCtxt::from_tcx(tcx);
- force_query::<queries::$name<'_>, _>(tcx, key, dep_node);
- true
- } else {
- false
- }
- }
-
- fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: DepNode) {
- 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));
- if queries::$name::cache_on_disk(tcx, &key) {
- let _ = tcx.$name(key);
- }
- }
-
- DepKindStruct {
- is_anon,
- is_eval_always,
- fingerprint_style,
- force_from_dep_node: Some(force_from_dep_node),
- try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache),
- }
+ $(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> {
+ $crate::plumbing::query_callback::<queries::$name<'tcx>>(
+ is_anon!([$($modifiers)*]),
+ is_eval_always!([$($modifiers)*]),
+ )
})*
}
- pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct] {
+ pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] {
arena.alloc_from_iter(make_dep_kind_array!(query_callbacks))
}
}
let mut jobs = QueryMap::default();
$(
+ let make_query = |tcx, key| {
+ let kind = dep_graph::DepKind::$name;
+ let name = stringify!($name);
+ $crate::plumbing::create_query_frame(tcx, queries::$name::describe, key, kind, name)
+ };
self.$name.try_collect_active_jobs(
tcx,
- make_query::$name,
+ make_query,
&mut jobs,
)?;
)*
$($(#[$attr])*
#[inline(always)]
- #[tracing::instrument(level = "trace", skip(self, tcx))]
+ #[tracing::instrument(level = "trace", skip(self, tcx), ret)]
fn $name(
&'tcx self,
tcx: TyCtxt<'tcx>,
fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVTable<CTX, Self::Key, Self::Value>;
fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool;
+
+ // Don't use this method to compute query results, instead use the methods on TyCtxt
+ fn execute_query(tcx: CTX::DepContext, k: Self::Key) -> Self::Stored;
}
+use crate::imports::ImportKind;
+use crate::NameBinding;
+use crate::NameBindingKind;
+use crate::Resolver;
use rustc_ast::ast;
use rustc_ast::visit;
use rustc_ast::visit::Visitor;
use rustc_ast::Crate;
use rustc_ast::EnumDef;
-use rustc_ast::ForeignMod;
use rustc_ast::NodeId;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_middle::middle::privacy::AccessLevel;
-use rustc_middle::ty::Visibility;
+use rustc_middle::ty::DefIdTree;
use rustc_span::sym;
-use crate::imports::ImportKind;
-use crate::BindingKey;
-use crate::NameBinding;
-use crate::NameBindingKind;
-use crate::Resolver;
-
pub struct AccessLevelsVisitor<'r, 'a> {
r: &'r mut Resolver<'a>,
- prev_level: Option<AccessLevel>,
changed: bool,
}
/// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
/// need access to a TyCtxt for that.
pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
- let mut visitor =
- AccessLevelsVisitor { r, changed: false, prev_level: Some(AccessLevel::Public) };
+ let mut visitor = AccessLevelsVisitor { r, changed: false };
visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public));
- visitor.set_exports_access_level(CRATE_DEF_ID);
+ visitor.set_bindings_access_level(CRATE_DEF_ID);
while visitor.changed {
visitor.reset();
visit::walk_crate(&mut visitor, krate);
}
- tracing::info!("resolve::access_levels: {:#?}", r.access_levels);
+ info!("resolve::access_levels: {:#?}", r.access_levels);
}
fn reset(&mut self) {
self.changed = false;
- self.prev_level = Some(AccessLevel::Public);
}
- /// Update the access level of the exports of the given module accordingly. The module access
+ /// Update the access level of the bindings in the given module accordingly. The module access
/// level has to be Exported or Public.
/// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
- fn set_exports_access_level(&mut self, module_id: LocalDefId) {
+ fn set_bindings_access_level(&mut self, module_id: LocalDefId) {
assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
-
+ let module_level = self.r.access_levels.map.get(&module_id).copied();
+ if !module_level.is_some() {
+ return;
+ }
// Set the given binding access level to `AccessLevel::Public` and
// sets the rest of the `use` chain to `AccessLevel::Exported` until
// we hit the actual exported item.
}
};
- let module_level = self.r.access_levels.map.get(&module_id).copied();
- assert!(module_level >= Some(AccessLevel::Exported));
-
- if let Some(exports) = self.r.reexport_map.get(&module_id) {
- let pub_exports = exports
- .iter()
- .filter(|ex| ex.vis == Visibility::Public)
- .cloned()
- .collect::<Vec<_>>();
-
- let module = self.r.get_module(module_id.to_def_id()).unwrap();
- for export in pub_exports.into_iter() {
- if let Some(export_def_id) = export.res.opt_def_id().and_then(|id| id.as_local()) {
- self.set_access_level_def_id(export_def_id, Some(AccessLevel::Exported));
- }
-
- if let Some(ns) = export.res.ns() {
- let key = BindingKey { ident: export.ident, ns, disambiguator: 0 };
- let name_res = self.r.resolution(module, key);
- if let Some(binding) = name_res.borrow().binding() {
- set_import_binding_access_level(self, binding, module_level)
- }
+ let module = self.r.get_module(module_id.to_def_id()).unwrap();
+ let resolutions = self.r.resolutions(module);
+
+ for (.., name_resolution) in resolutions.borrow().iter() {
+ if let Some(binding) = name_resolution.borrow().binding() && binding.vis.is_public() && !binding.is_ambiguity() {
+ let access_level = match binding.is_import() {
+ true => {
+ set_import_binding_access_level(self, binding, module_level);
+ Some(AccessLevel::Exported)
+ },
+ false => module_level,
+ };
+ if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
+ self.set_access_level_def_id(def_id, access_level);
}
}
}
impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
fn visit_item(&mut self, item: &'ast ast::Item) {
- let inherited_item_level = match item.kind {
+ let def_id = self.r.local_def_id(item.id);
+ // Set access level of nested items.
+ // If it's a mod, also make the visitor walk all of its items
+ match item.kind {
// Resolved in rustc_privacy when types are available
ast::ItemKind::Impl(..) => return,
- // Only exported `macro_rules!` items are public, but they always are
- ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
- let is_macro_export =
- item.attrs.iter().any(|attr| attr.has_name(sym::macro_export));
- if is_macro_export { Some(AccessLevel::Public) } else { None }
- }
-
- // Foreign modules inherit level from parents.
- ast::ItemKind::ForeignMod(..) => self.prev_level,
-
- // Other `pub` items inherit levels from parents.
- ast::ItemKind::ExternCrate(..)
- | ast::ItemKind::Use(..)
- | ast::ItemKind::Static(..)
- | ast::ItemKind::Const(..)
- | ast::ItemKind::Fn(..)
- | ast::ItemKind::Mod(..)
- | ast::ItemKind::GlobalAsm(..)
- | ast::ItemKind::TyAlias(..)
- | ast::ItemKind::Enum(..)
- | ast::ItemKind::Struct(..)
- | ast::ItemKind::Union(..)
- | ast::ItemKind::Trait(..)
- | ast::ItemKind::TraitAlias(..)
- | ast::ItemKind::MacroDef(..) => {
- if item.vis.kind.is_pub() {
- self.prev_level
- } else {
- None
- }
- }
-
// Should be unreachable at this stage
ast::ItemKind::MacCall(..) => panic!(
"ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
),
- };
- let access_level = self.set_access_level(item.id, inherited_item_level);
+ // Foreign modules inherit level from parents.
+ ast::ItemKind::ForeignMod(..) => {
+ let parent_level =
+ self.r.access_levels.map.get(&self.r.local_parent(def_id)).copied();
+ self.set_access_level(item.id, parent_level);
+ }
- // Set access level of nested items.
- // If it's a mod, also make the visitor walk all of its items
- match item.kind {
- ast::ItemKind::Mod(..) => {
- if access_level.is_some() {
- self.set_exports_access_level(self.r.local_def_id(item.id));
+ // Only exported `macro_rules!` items are public, but they always are
+ ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
+ if item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)) {
+ self.set_access_level(item.id, Some(AccessLevel::Public));
}
+ }
- let orig_level = std::mem::replace(&mut self.prev_level, access_level);
+ ast::ItemKind::Mod(..) => {
+ self.set_bindings_access_level(def_id);
visit::walk_item(self, item);
- self.prev_level = orig_level;
}
- ast::ItemKind::ForeignMod(ForeignMod { ref items, .. }) => {
- for nested in items {
- if nested.vis.kind.is_pub() {
- self.set_access_level(nested.id, access_level);
- }
- }
- }
ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
+ self.set_bindings_access_level(def_id);
for variant in variants {
- let variant_level = self.set_access_level(variant.id, access_level);
- if let Some(ctor_id) = variant.data.ctor_id() {
- self.set_access_level(ctor_id, access_level);
- }
-
+ let variant_def_id = self.r.local_def_id(variant.id);
+ let variant_level = self.r.access_levels.map.get(&variant_def_id).copied();
for field in variant.data.fields() {
self.set_access_level(field.id, variant_level);
}
}
}
- ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
- if let Some(ctor_id) = def.ctor_id() {
- self.set_access_level(ctor_id, access_level);
- }
+ ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
+ let inherited_level = self.r.access_levels.map.get(&def_id).copied();
for field in def.fields() {
if field.vis.kind.is_pub() {
- self.set_access_level(field.id, access_level);
+ self.set_access_level(field.id, inherited_level);
}
}
}
- ast::ItemKind::Trait(ref trait_kind) => {
- for nested in trait_kind.items.iter() {
- self.set_access_level(nested.id, access_level);
- }
+
+ ast::ItemKind::Trait(..) => {
+ self.set_bindings_access_level(def_id);
}
ast::ItemKind::ExternCrate(..)
| ast::ItemKind::TraitAlias(..)
| ast::ItemKind::MacroDef(..)
| ast::ItemKind::Fn(..) => return,
-
- // Unreachable kinds
- ast::ItemKind::Impl(..) | ast::ItemKind::MacCall(..) => unreachable!(),
}
}
}
use std::cell::Cell;
use std::ptr;
-use tracing::debug;
type Res = def::Res<NodeId>;
self.insert_field_names(def_id, field_names);
}
Res::Def(DefKind::AssocFn, def_id) => {
- if cstore.fn_has_self_parameter_untracked(def_id) {
+ if cstore.fn_has_self_parameter_untracked(def_id, self.r.session) {
self.r.has_self.insert(def_id);
}
}
use rustc_span::hygiene::LocalExpnId;
use rustc_span::symbol::sym;
use rustc_span::Span;
-use tracing::debug;
pub(crate) fn collect_definitions(
resolver: &mut Resolver<'_>,
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Span};
-use tracing::debug;
use crate::imports::{Import, ImportKind, ImportResolver};
use crate::late::{PatternSource, Rib};
// If only some candidates are accessible, take just them
if !candidates.iter().all(|v: &ImportSuggestion| !v.accessible) {
- candidates = candidates.into_iter().filter(|x| x.accessible).collect();
+ candidates.retain(|x| x.accessible)
}
candidates
///
/// Invariant: This must only be called during main resolution, not during
/// import resolution.
- #[tracing::instrument(level = "debug", skip(self, ribs))]
+ #[instrument(level = "debug", skip(self, ribs))]
pub(crate) fn resolve_ident_in_lexical_scope(
&mut self,
mut ident: Ident,
/// expansion and import resolution (perhaps they can be merged in the future).
/// The function is used for resolving initial segments of macro paths (e.g., `foo` in
/// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition.
- #[tracing::instrument(level = "debug", skip(self, scope_set))]
+ #[instrument(level = "debug", skip(self, scope_set))]
pub(crate) fn early_resolve_ident_in_lexical_scope(
&mut self,
orig_ident: Ident,
Err(Determinacy::determined(determinacy == Determinacy::Determined || force))
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn maybe_resolve_ident_in_module(
&mut self,
module: ModuleOrUniformRoot<'a>,
.map_err(|(determinacy, _)| determinacy)
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn resolve_ident_in_module(
&mut self,
module: ModuleOrUniformRoot<'a>,
.map_err(|(determinacy, _)| determinacy)
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn resolve_ident_in_module_ext(
&mut self,
module: ModuleOrUniformRoot<'a>,
)
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn resolve_ident_in_module_unadjusted(
&mut self,
module: ModuleOrUniformRoot<'a>,
/// Attempts to resolve `ident` in namespaces `ns` of `module`.
/// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete.
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn resolve_ident_in_module_unadjusted_ext(
&mut self,
module: ModuleOrUniformRoot<'a>,
}
/// Validate a local resolution (from ribs).
- #[tracing::instrument(level = "debug", skip(self, all_ribs))]
+ #[instrument(level = "debug", skip(self, all_ribs))]
fn validate_res_from_ribs(
&mut self,
rib_index: usize,
res
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn maybe_resolve_path(
&mut self,
path: &[Segment],
self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None)
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn resolve_path(
&mut self,
path: &[Segment],
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span;
-use tracing::*;
-
use std::cell::Cell;
use std::{mem, ptr};
if let Some(def_id) = module.opt_def_id() {
let mut reexports = Vec::new();
- module.for_each_child(self.r, |_, ident, _, binding| {
- // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules`
- // into the crate root to actual `NameBindingKind::Import`.
- if binding.is_import()
- || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true))
- {
- let res = binding.res().expect_non_local();
- // Ambiguous imports are treated as errors at this point and are
- // not exposed to other crates (see #36837 for more details).
- if res != def::Res::Err && !binding.is_ambiguity() {
- reexports.push(ModChild {
- ident,
- res,
- vis: binding.vis,
- span: binding.span,
- macro_rules: false,
- });
- }
+ module.for_each_child(self.r, |this, ident, _, binding| {
+ if let Some(res) = this.is_reexport(binding) {
+ reexports.push(ModChild {
+ ident,
+ res,
+ vis: binding.vis,
+ span: binding.span,
+ macro_rules: false,
+ });
}
});
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
-use rustc_hir::{PrimTy, TraitCandidate};
+use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
use rustc_middle::middle::resolve_lifetime::Set1;
use rustc_middle::ty::DefIdTree;
use rustc_middle::{bug, span_bug};
use rustc_span::source_map::{respan, Spanned};
use std::collections::{hash_map::Entry, BTreeSet};
use std::mem::{replace, take};
-use tracing::debug;
mod diagnostics;
pub(crate) mod lifetimes;
#[derive(Copy, Clone, Debug)]
struct BindingInfo {
span: Span,
- binding_mode: BindingMode,
+ annotation: BindingAnnotation,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
})
}
- #[tracing::instrument(level = "debug", skip(self, work))]
+ #[instrument(level = "debug", skip(self, work))]
fn with_lifetime_rib<T>(
&mut self,
kind: LifetimeRibKind,
ret
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::LifetimeCtxt) {
let ident = lifetime.ident;
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named);
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
let id = self.r.next_node_id();
let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
self.resolve_anonymous_lifetime(<, true);
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, binder: NodeId) -> LifetimeRes {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
debug!(?ident.span);
res
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn resolve_elided_lifetimes_in_path(
&mut self,
path_id: NodeId,
}
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn record_lifetime_res(
&mut self,
id: NodeId,
}
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) {
if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
panic!(
}
/// Perform resolution of a function signature, accounting for lifetime elision.
- #[tracing::instrument(level = "debug", skip(self, inputs))]
+ #[instrument(level = "debug", skip(self, inputs))]
fn resolve_fn_signature(
&mut self,
fn_id: NodeId,
pat.walk(&mut |pat| {
match pat.kind {
- PatKind::Ident(binding_mode, ident, ref sub_pat)
+ PatKind::Ident(annotation, ident, ref sub_pat)
if sub_pat.is_some() || self.is_base_res_local(pat.id) =>
{
- binding_map.insert(ident, BindingInfo { span: ident.span, binding_mode });
+ binding_map.insert(ident, BindingInfo { span: ident.span, annotation });
}
PatKind::Or(ref ps) => {
// Check the consistency of this or-pattern and
binding_error.target.insert(pat_outer.span);
}
Some(binding_outer) => {
- if binding_outer.binding_mode != binding_inner.binding_mode {
+ if binding_outer.annotation != binding_inner.annotation {
// The binding modes in the outer and inner bindings differ.
inconsistent_vars
.entry(name)
fn try_resolve_as_non_binding(
&mut self,
pat_src: PatternSource,
- bm: BindingMode,
+ ann: BindingAnnotation,
ident: Ident,
has_sub: bool,
) -> Option<Res> {
// An immutable (no `mut`) by-value (no `ref`) binding pattern without
// a sub pattern (no `@ $pat`) is syntactically ambiguous as it could
// also be interpreted as a path to e.g. a constant, variant, etc.
- let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not);
+ let is_syntactic_ambiguity = !has_sub && ann == BindingAnnotation::NONE;
let ls_binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS)?;
let (res, binding) = match ls_binding {
source: PathSource<'ast>,
finalize: Finalize,
) -> PartialRes {
- tracing::debug!(
+ debug!(
"smart_resolve_path_fragment(qself={:?}, path={:?}, finalize={:?})",
- qself,
- path,
- finalize,
+ qself, path, finalize,
);
let ns = source.namespace();
use std::iter;
use std::ops::Deref;
-use tracing::debug;
-
type Res = def::Res<ast::NodeId>;
/// A field or associated item from self type suggested in case of resolution failure.
/// lifetimes into a single binder.) This requires us to resolve the
/// *trait definition* of `Sub`; basically just enough lifetime information
/// to look at the supertraits.
-#[tracing::instrument(level = "debug", skip(tcx))]
+#[instrument(level = "debug", skip(tcx))]
fn resolve_lifetimes_trait_definition(
tcx: TyCtxt<'_>,
local_def_id: LocalDefId,
/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
/// You should not read the result of this query directly, but rather use
/// `named_region_map`, `is_late_bound_map`, etc.
-#[tracing::instrument(level = "debug", skip(tcx))]
+#[instrument(level = "debug", skip(tcx))]
fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
convert_named_region_map(do_resolve(tcx, local_def_id, false))
}
}
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
match ty.kind {
hir::TyKind::BareFn(ref c) => {
}
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
match lifetime_ref.name {
hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
}
}
-fn object_lifetime_default<'tcx>(
- tcx: TyCtxt<'tcx>,
- param_def_id: DefId,
-) -> Option<ObjectLifetimeDefault> {
+fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> ObjectLifetimeDefault {
+ debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam);
let param_def_id = param_def_id.expect_local();
let parent_def_id = tcx.local_parent(param_def_id);
- let generics = tcx.hir().get_generics(parent_def_id)?;
+ let generics = tcx.hir().get_generics(parent_def_id).unwrap();
let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id);
- let param = generics.params.iter().find(|p| p.hir_id == param_hir_id)?;
+ let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap();
// Scan the bounds and where-clauses on parameters to extract bounds
// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
// for each type parameter.
match param.kind {
- GenericParamKind::Lifetime { .. } => None,
GenericParamKind::Type { .. } => {
let mut set = Set1::Empty;
}
}
- Some(match set {
+ match set {
Set1::Empty => ObjectLifetimeDefault::Empty,
Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
Set1::One(hir::LifetimeName::Param(param_def_id, _)) => {
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
}
_ => ObjectLifetimeDefault::Ambiguous,
- })
+ }
}
- GenericParamKind::Const { .. } => {
- // Generic consts don't impose any constraints.
- //
- // We still store a dummy value here to allow generic parameters
- // in an arbitrary order.
- Some(ObjectLifetimeDefault::Empty)
+ _ => {
+ bug!("object_lifetime_default_raw must only be called on a type parameter")
}
}
}
scope: &wrap_scope,
trait_definition_only: self.trait_definition_only,
};
- let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
+ let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
{
let _enter = span.enter();
f(&mut this);
self.with(scope, walk);
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn resolve_lifetime_ref(
&mut self,
region_def_id: LocalDefId,
);
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn visit_segment_args(
&mut self,
res: Res,
generics
.params
.iter()
- .filter_map(|param| self.tcx.object_lifetime_default(param.def_id))
+ .filter_map(|param| {
+ match self.tcx.def_kind(param.def_id) {
+ // Generic consts don't impose any constraints.
+ //
+ // We still store a dummy value here to allow generic parameters
+ // in an arbitrary order.
+ DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty),
+ DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)),
+ // We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter
+ // works. Ignore it because it can't have a meaningful lifetime default.
+ DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None,
+ dk => bug!("unexpected def_kind {:?}", dk),
+ }
+ })
.map(set_to_region)
.collect()
});
}
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn visit_fn_like_elision(
&mut self,
inputs: &'tcx [hir::Ty<'tcx>],
self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
debug!(
node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id),
use std::cell::{Cell, RefCell};
use std::collections::BTreeSet;
use std::{cmp, fmt, ptr};
-use tracing::debug;
use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
use imports::{Import, ImportKind, ImportResolver, NameResolution};
label_res_map: NodeMap<NodeId>,
/// Resolutions for lifetimes.
lifetimes_res_map: NodeMap<LifetimeRes>,
- /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
- /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
- /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
- /// field from the original parameter 'a to the new parameter 'a1.
- generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
/// Lifetime parameters that lowering will have to introduce.
extra_lifetime_params_map: NodeMap<Vec<(Ident, NodeId, LifetimeRes)>>,
import_res_map: Default::default(),
label_res_map: Default::default(),
lifetimes_res_map: Default::default(),
- generics_def_id_map: Vec::new(),
extra_lifetime_params_map: Default::default(),
extern_crate_map: Default::default(),
reexport_map: FxHashMap::default(),
import_res_map: self.import_res_map,
label_res_map: self.label_res_map,
lifetimes_res_map: self.lifetimes_res_map,
- generics_def_id_map: self.generics_def_id_map,
extra_lifetime_params_map: self.extra_lifetime_params_map,
next_node_id: self.next_node_id,
node_id_to_def_id: self.node_id_to_def_id,
import_res_map: self.import_res_map.clone(),
label_res_map: self.label_res_map.clone(),
lifetimes_res_map: self.lifetimes_res_map.clone(),
- generics_def_id_map: self.generics_def_id_map.clone(),
extra_lifetime_params_map: self.extra_lifetime_params_map.clone(),
next_node_id: self.next_node_id.clone(),
node_id_to_def_id: self.node_id_to_def_id.clone(),
}
self.main_def = Some(MainDefinition { res, is_import, span });
}
+
+ // Items that go to reexport table encoded to metadata and visible through it to other crates.
+ fn is_reexport(&self, binding: &NameBinding<'a>) -> Option<def::Res<!>> {
+ // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules`
+ // into the crate root to actual `NameBindingKind::Import`.
+ if binding.is_import()
+ || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true))
+ {
+ let res = binding.res().expect_non_local();
+ // Ambiguous imports are treated as errors at this point and are
+ // not exposed to other crates (see #36837 for more details).
+ if res != def::Res::Err && !binding.is_ambiguity() {
+ return Some(res);
+ }
+ }
+
+ return None;
+ }
}
fn names_to_string(names: &[Symbol]) -> String {
RefKind, Relation, RelationKind, SpanData,
};
-use tracing::{debug, error};
-
#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5213
macro_rules! down_cast_data {
($id:ident, $kind:ident, $sp:expr) => {
&mut self,
ex: &'tcx hir::Expr<'tcx>,
seg: &'tcx hir::PathSegment<'tcx>,
+ receiver: &'tcx hir::Expr<'tcx>,
args: &'tcx [hir::Expr<'tcx>],
) {
debug!("process_method_call {:?} {:?}", ex, ex.span);
}
// walk receiver and args
+ self.visit_expr(receiver);
walk_list!(self, visit_expr, args);
}
_,
)
| Res::SelfTy { .. } => {
- self.dump_path_segment_ref(id, &hir::PathSegment::from_ident(ident));
+ self.dump_path_segment_ref(
+ id,
+ &hir::PathSegment::new(ident, hir::HirId::INVALID, Res::Err),
+ );
}
def => {
error!("unexpected definition kind when processing collected idents: {:?}", def)
self.process_macro_use(trait_item.span);
match trait_item.kind {
hir::TraitItemKind::Const(ref ty, body) => {
- let body = body.map(|b| &self.tcx.hir().body(b).value);
+ let body = body.map(|b| self.tcx.hir().body(b).value);
let attrs = self.tcx.hir().attrs(trait_item.hir_id());
self.process_assoc_const(
trait_item.def_id,
let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *rest)
}
- hir::ExprKind::MethodCall(ref seg, args, _) => self.process_method_call(ex, seg, args),
+ hir::ExprKind::MethodCall(ref seg, receiver, args, _) => {
+ self.process_method_call(ex, seg, receiver, args)
+ }
hir::ExprKind::Field(ref sub_ex, _) => {
self.visit_expr(&sub_ex);
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
+#[macro_use]
+extern crate tracing;
+
mod dump_visitor;
mod dumper;
#[macro_use]
RefKind, Relation, RelationKind, SpanData,
};
-use tracing::{debug, error, info};
-
pub struct SaveContext<'tcx> {
tcx: TyCtxt<'tcx>,
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
Node::TraitRef(tr) => tr.path.res,
Node::Item(&hir::Item { kind: hir::ItemKind::Use(path, _), .. }) => path.res,
- Node::PathSegment(seg) => match seg.res {
- Some(res) if res != Res::Err => res,
- _ => {
+ Node::PathSegment(seg) => {
+ if seg.res != Res::Err {
+ seg.res
+ } else {
let parent_node = self.tcx.hir().get_parent_node(hir_id);
self.get_path_res(parent_node)
}
- },
+ }
Node::Expr(&hir::Expr { kind: hir::ExprKind::Struct(ref qpath, ..), .. }) => {
self.typeck_results().qpath_res(qpath, hir_id)
}
pub fn get_path_segment_data(&self, path_seg: &hir::PathSegment<'_>) -> Option<Ref> {
- self.get_path_segment_data_with_id(path_seg, path_seg.hir_id?)
+ self.get_path_segment_data_with_id(path_seg, path_seg.hir_id)
}
pub fn get_path_segment_data_with_id(
hir::PatKind::TupleStruct(ref path, ..) | hir::PatKind::Path(ref path) => {
self.collected_paths.push((p.hir_id, path));
}
- hir::PatKind::Binding(bm, _, ident, _) => {
+ hir::PatKind::Binding(hir::BindingAnnotation(_, mutbl), _, ident, _) => {
debug!(
"PathCollector, visit ident in pat {}: {:?} {:?}",
ident, p.span, ident.span
);
- let immut = match bm {
- // Even if the ref is mut, you can't change the ref, only
- // the data pointed at, so showing the initialising expression
- // is still worthwhile.
- hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Ref => {
- hir::Mutability::Not
- }
- hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut => {
- hir::Mutability::Mut
- }
- };
- self.collected_idents.push((p.hir_id, ident, immut));
+ self.collected_idents.push((p.hir_id, ident, mutbl));
}
_ => {}
}
use std::borrow::Cow;
use std::fmt::{self};
use std::sync::{Arc, Mutex};
-use tracing::debug;
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub enum CguReuse {
use rustc_data_structures::stable_hasher::ToStableHashKey;
use rustc_target::abi::{Align, TargetDataLayout};
-use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
-use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS};
+use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
+use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
use crate::parse::{CrateCheckConfig, CrateConfig};
use rustc_feature::UnstableFeatures;
use std::path::{Path, PathBuf};
use std::str::{self, FromStr};
+pub mod sigpipe;
+
/// The different settings that the `-C strip` flag can have.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum Strip {
// The type of entry function, so users can have their own entry functions
#[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
pub enum EntryFnType {
- Main,
+ Main {
+ /// Specifies what to do with `SIGPIPE` before calling `fn main()`.
+ ///
+ /// What values that are valid and what they mean must be in sync
+ /// across rustc and libstd, but we don't want it public in libstd,
+ /// so we take a bit of an unusual approach with simple constants
+ /// and an `include!()`.
+ sigpipe: u8,
+ },
Start,
}
sess.fatal(&err);
});
- let mut ret = FxHashSet::default();
+ let mut ret = CrateConfig::default();
ret.reserve(7); // the minimum number of insertions
// Target bindings.
ret.insert((sym::target_os, Some(Symbol::intern(os))));
}
}
- if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
- && !nightly_options::is_unstable_enabled(matches)
- {
- early_error(
- error_format,
- "`l4-bender` linker flavor is unstable, `-Z unstable-options` \
- flag must also be passed to explicitly use it",
- );
- }
-
let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
let cg = cg;
),
),
};
- tracing::debug!("got unpretty option: {first:?}");
+ debug!("got unpretty option: {first:?}");
Some(first)
}
--- /dev/null
+//! NOTE: Keep these constants in sync with `library/std/src/sys/unix/mod.rs`!
+
+/// Do not touch `SIGPIPE`. Use whatever the parent process uses.
+#[allow(dead_code)]
+pub const INHERIT: u8 = 1;
+
+/// Change `SIGPIPE` to `SIG_IGN` so that failed writes results in `EPIPE`
+/// that are eventually converted to `ErrorKind::BrokenPipe`.
+#[allow(dead_code)]
+pub const SIG_IGN: u8 = 2;
+
+/// Change `SIGPIPE` to `SIG_DFL` so that the process is killed when trying
+/// to write to a closed pipe. This is usually the desired behavior for CLI
+/// apps that produce textual output that you want to pipe to other programs
+/// such as `head -n 1`.
+#[allow(dead_code)]
+pub const SIG_DFL: u8 = 3;
+
+/// `SIG_IGN` has been the Rust default since 2014. See
+/// <https://github.com/rust-lang/rust/issues/62569>.
+#[allow(dead_code)]
+pub const DEFAULT: u8 = SIG_IGN;
use crate::search_paths::{PathKind, SearchPath};
use rustc_fs_util::fix_windows_verbatim_for_gcc;
-use tracing::debug;
#[derive(Copy, Clone)]
pub enum FileMatch {
extern crate rustc_macros;
pub mod errors;
+#[macro_use]
+extern crate tracing;
+
pub mod cgu_reuse_tracker;
pub mod utils;
pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass};
use crate::search_paths::SearchPath;
use crate::utils::NativeLib;
use rustc_errors::LanguageIdentifier;
-use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
+use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
use rustc_target::spec::{
RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
};
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
- pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
+ pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
pub const parse_optimization_fuel: &str = "crate=integer";
pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
pub const parse_instrument_coverage: &str =
true
}
- pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
- match v.and_then(LinkerFlavor::from_str) {
+ pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool {
+ match v.and_then(LinkerFlavorCli::from_str) {
Some(lf) => *slot = Some(lf),
_ => return false,
}
on C toolchain installed in the system"),
linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"system linker to link outputs with"),
- linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
+ linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED],
"linker flavor"),
linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
parse_linker_plugin_lto, [TRACKED],
};
use crate::SessionDiagnostic;
use rustc_ast::node_id::NodeId;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
use rustc_errors::{
/// The set of keys (and, optionally, values) that define the compilation
/// environment of the crate, used to drive conditional compilation.
-pub type CrateConfig = FxHashSet<(Symbol, Option<Symbol>)>;
+pub type CrateConfig = FxIndexSet<(Symbol, Option<Symbol>)>;
pub type CrateCheckConfig = CheckCfg<Symbol>;
/// Collected spans during parsing for places where a certain feature was
Self {
span_diagnostic: handler,
unstable_features: UnstableFeatures::from_environment(None),
- config: FxHashSet::default(),
+ config: FxIndexSet::default(),
check_config: CrateCheckConfig::default(),
edition: ExpnId::root().expn_data().edition,
raw_identifier_spans: Lock::new(Vec::new()),
}
}
+impl rustc_errors::IntoDiagnosticArg for Limit {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ self.to_string().into_diagnostic_arg()
+ }
+}
+
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub struct Limits {
/// The maximum recursion limit for potentially infinitely recursive
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
use std::hash::Hash;
-use tracing::*;
/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
use sha1::Sha1;
use sha2::Sha256;
-use tracing::debug;
-
#[cfg(test)]
mod tests;
use std::fs;
use std::io;
-use tracing::debug;
#[cfg(test)]
mod tests;
return remap_path_prefix(&self.mapping, path);
- #[instrument(level = "debug", skip(mapping))]
+ #[instrument(level = "debug", skip(mapping), ret)]
fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf, bool) {
// NOTE: We are iterating over the mapping entries from last to first
// because entries specified later on the command line should
// take precedence.
for &(ref from, ref to) in mapping.iter().rev() {
- debug!("Trying to apply {:?} => {:?}", from, to);
+ debug!("Trying to apply {from:?} => {to:?}");
if let Ok(rest) = path.strip_prefix(from) {
let remapped = if rest.as_os_str().is_empty() {
} else {
to.join(rest)
};
- debug!("Match - remapped {:?} => {:?}", path, remapped);
+ debug!("Match - remapped");
return (remapped, true);
} else {
- debug!("No match - prefix {:?} does not match {:?}", from, path);
+ debug!("No match - prefix {from:?} does not match");
}
}
- debug!("Path {:?} was not remapped", path);
+ debug!("not remapped");
(path, false)
}
}
LinkedList,
LintPass,
Mutex,
+ MutexGuard,
N,
NonZeroI128,
NonZeroI16,
Rust,
RustcDecodable,
RustcEncodable,
+ RwLockReadGuard,
+ RwLockWriteGuard,
Send,
SeqCst,
SessionDiagnostic,
alias,
align,
align_offset,
+ alignment,
alignstack,
all,
alloc,
const_deallocate,
const_eval_limit,
const_eval_select,
- const_eval_select_ct,
const_evaluatable_checked,
const_extern_fn,
const_fn,
emit_struct,
emit_struct_field,
enable,
- enclosing_scope,
encode,
end,
env,
infer_outlives_requirements,
infer_static_outlives_requirements,
inherent_associated_types,
+ inherit,
inlateout,
inline,
inline_const,
lib,
libc,
lifetime,
+ lifetimes,
likely,
line,
line_macro,
panic_unwind,
panicking,
param_attrs,
+ parent_label,
partial_cmp,
partial_ord,
passes,
rust_eh_unregister_frames,
rust_oom,
rustc,
+ rustc_access_level,
rustc_allocator,
rustc_allocator_nounwind,
rustc_allocator_zeroed,
rustfmt,
rvalue_static_promotion,
s,
+ safety,
sanitize,
sanitizer_runtime,
saturating_add,
should_panic,
shr,
shr_assign,
+ sig_dfl,
+ sig_ign,
simd,
simd_add,
simd_and,
trait_alias,
trait_upcasting,
transmute,
+ transmute_opts,
transmute_trait,
transparent,
transparent_enums,
unit,
universal_impl_trait,
unix,
+ unix_sigpipe,
unlikely,
unmarked_api,
unpin,
va_list,
va_start,
val,
+ validity,
values,
var,
variant_count,
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitable};
use rustc_middle::util::common::record_time;
-use tracing::debug;
-
use std::fmt::{self, Write};
use std::mem::{self, discriminant};
#[macro_use]
extern crate rustc_middle;
+#[macro_use]
+extern crate tracing;
+
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::{self, Instance, TyCtxt};
use rustc_session::config::SymbolManglingVersion;
-use tracing::debug;
-
mod legacy;
mod v0;
pub fn target() -> Target {
let mut target = wasm32_unknown_emscripten::target();
- target.add_post_link_args(LinkerFlavor::Em, &["-sWASM=0", "--memory-init-file", "0"]);
+ target.add_post_link_args(LinkerFlavor::EmCc, &["-sWASM=0", "--memory-init-file", "0"]);
target
}
TargetOptions {
allow_asm: true,
endian,
- linker_flavor: LinkerFlavor::BpfLinker,
+ linker_flavor: LinkerFlavor::Bpf,
atomic_cas: false,
dynamic_linking: true,
no_builtins: true,
TargetOptions {
os: "l4re".into(),
env: "uclibc".into(),
- linker_flavor: LinkerFlavor::L4Bender,
+ linker_flavor: LinkerFlavor::Ld,
panic_strategy: PanicStrategy::Abort,
linker: Some("l4-bender".into()),
linker_is_gnu: false,
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LinkerFlavor {
- Em,
Gcc,
- L4Bender,
Ld,
+ Lld(LldFlavor),
Msvc,
+ EmCc,
+ Bpf,
+ Ptx,
+}
+
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
+pub enum LinkerFlavorCli {
+ Gcc,
+ Ld,
Lld(LldFlavor),
- PtxLinker,
+ Msvc,
+ Em,
BpfLinker,
+ PtxLinker,
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
}
}
-impl ToJson for LinkerFlavor {
- fn to_json(&self) -> Json {
- self.desc().to_json()
+impl LinkerFlavor {
+ pub fn from_cli(cli: LinkerFlavorCli) -> LinkerFlavor {
+ match cli {
+ LinkerFlavorCli::Gcc => LinkerFlavor::Gcc,
+ LinkerFlavorCli::Ld => LinkerFlavor::Ld,
+ LinkerFlavorCli::Lld(lld_flavor) => LinkerFlavor::Lld(lld_flavor),
+ LinkerFlavorCli::Msvc => LinkerFlavor::Msvc,
+ LinkerFlavorCli::Em => LinkerFlavor::EmCc,
+ LinkerFlavorCli::BpfLinker => LinkerFlavor::Bpf,
+ LinkerFlavorCli::PtxLinker => LinkerFlavor::Ptx,
+ }
+ }
+
+ fn to_cli(self) -> LinkerFlavorCli {
+ match self {
+ LinkerFlavor::Gcc => LinkerFlavorCli::Gcc,
+ LinkerFlavor::Ld => LinkerFlavorCli::Ld,
+ LinkerFlavor::Lld(lld_flavor) => LinkerFlavorCli::Lld(lld_flavor),
+ LinkerFlavor::Msvc => LinkerFlavorCli::Msvc,
+ LinkerFlavor::EmCc => LinkerFlavorCli::Em,
+ LinkerFlavor::Bpf => LinkerFlavorCli::BpfLinker,
+ LinkerFlavor::Ptx => LinkerFlavorCli::PtxLinker,
+ }
}
}
-macro_rules! flavor_mappings {
- ($((($($flavor:tt)*), $string:expr),)*) => (
- impl LinkerFlavor {
+
+macro_rules! linker_flavor_cli_impls {
+ ($(($($flavor:tt)*) $string:literal)*) => (
+ impl LinkerFlavorCli {
pub const fn one_of() -> &'static str {
concat!("one of: ", $($string, " ",)*)
}
- pub fn from_str(s: &str) -> Option<Self> {
+ pub fn from_str(s: &str) -> Option<LinkerFlavorCli> {
Some(match s {
$($string => $($flavor)*,)*
_ => return None,
)
}
-flavor_mappings! {
- ((LinkerFlavor::Em), "em"),
- ((LinkerFlavor::Gcc), "gcc"),
- ((LinkerFlavor::L4Bender), "l4-bender"),
- ((LinkerFlavor::Ld), "ld"),
- ((LinkerFlavor::Msvc), "msvc"),
- ((LinkerFlavor::PtxLinker), "ptx-linker"),
- ((LinkerFlavor::BpfLinker), "bpf-linker"),
- ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"),
- ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"),
- ((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"),
- ((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"),
+linker_flavor_cli_impls! {
+ (LinkerFlavorCli::Gcc) "gcc"
+ (LinkerFlavorCli::Ld) "ld"
+ (LinkerFlavorCli::Lld(LldFlavor::Ld)) "ld.lld"
+ (LinkerFlavorCli::Lld(LldFlavor::Ld64)) "ld64.lld"
+ (LinkerFlavorCli::Lld(LldFlavor::Link)) "lld-link"
+ (LinkerFlavorCli::Lld(LldFlavor::Wasm)) "wasm-ld"
+ (LinkerFlavorCli::Msvc) "msvc"
+ (LinkerFlavorCli::Em) "em"
+ (LinkerFlavorCli::BpfLinker) "bpf-linker"
+ (LinkerFlavorCli::PtxLinker) "ptx-linker"
+}
+
+impl ToJson for LinkerFlavorCli {
+ fn to_json(&self) -> Json {
+ self.desc().to_json()
+ }
}
#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)]
}
pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>;
+pub type LinkArgsCli = BTreeMap<LinkerFlavorCli, Vec<StaticCow<str>>>;
/// Which kind of debuginfo does the target use?
///
pub abi: StaticCow<str>,
/// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown".
pub vendor: StaticCow<str>,
- /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
- /// on the command line. Defaults to `LinkerFlavor::Gcc`.
- pub linker_flavor: LinkerFlavor,
/// Linker to invoke
pub linker: Option<StaticCow<str>>,
-
+ /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
+ /// on the command line. Defaults to `LinkerFlavor::Gcc`.
+ pub linker_flavor: LinkerFlavor,
+ linker_flavor_json: LinkerFlavorCli,
/// LLD flavor used if `lld` (or `rust-lld`) is specified as a linker
/// without clarifying its flavor in any way.
+ /// FIXME: Merge this into `LinkerFlavor`.
pub lld_flavor: LldFlavor,
+ /// Whether the linker support GNU-like arguments such as -O. Defaults to true.
+ /// FIXME: Merge this into `LinkerFlavor`.
+ pub linker_is_gnu: bool,
- /// Linker arguments that are passed *before* any user-defined libraries.
- pub pre_link_args: LinkArgs,
/// Objects to link before and after all other object code.
pub pre_link_objects: CrtObjects,
pub post_link_objects: CrtObjects,
pub post_link_objects_self_contained: CrtObjects,
pub link_self_contained: LinkSelfContainedDefault,
+ /// Linker arguments that are passed *before* any user-defined libraries.
+ pub pre_link_args: LinkArgs,
+ pre_link_args_json: LinkArgsCli,
/// Linker arguments that are unconditionally passed after any
/// user-defined but before post-link objects. Standard platform
/// libraries that should be always be linked to, usually go here.
pub late_link_args: LinkArgs,
+ late_link_args_json: LinkArgsCli,
/// Linker arguments used in addition to `late_link_args` if at least one
/// Rust dependency is dynamically linked.
pub late_link_args_dynamic: LinkArgs,
+ late_link_args_dynamic_json: LinkArgsCli,
/// Linker arguments used in addition to `late_link_args` if all Rust
/// dependencies are statically linked.
pub late_link_args_static: LinkArgs,
+ late_link_args_static_json: LinkArgsCli,
/// Linker arguments that are unconditionally passed *after* any
/// user-defined libraries.
pub post_link_args: LinkArgs,
+ post_link_args_json: LinkArgsCli,
+
/// Optional link script applied to `dylib` and `executable` crate types.
/// This is a string containing the script, not a path. Can only be applied
/// to linkers where `linker_is_gnu` is true.
pub link_script: Option<StaticCow<str>>,
-
/// Environment variables to be set for the linker invocation.
pub link_env: StaticCow<[(StaticCow<str>, StaticCow<str>)]>,
/// Environment variables to be removed for the linker invocation.
/// Default supported version of DWARF on this platform.
/// Useful because some platforms (osx, bsd) only want up to DWARF2.
pub default_dwarf_version: u32,
- /// Whether the linker support GNU-like arguments such as -O. Defaults to true.
- pub linker_is_gnu: bool,
/// The MinGW toolchain has a known issue that prevents it from correctly
/// handling COFF object files with more than 2<sup>15</sup> sections. Since each weak
/// symbol needs its own COMDAT section, weak linkage implies a large
LinkerFlavor::Lld(lld_flavor) => {
panic!("add_link_args: use non-LLD flavor for {:?}", lld_flavor)
}
- LinkerFlavor::Gcc
- | LinkerFlavor::Em
- | LinkerFlavor::L4Bender
- | LinkerFlavor::BpfLinker
- | LinkerFlavor::PtxLinker => {}
+ LinkerFlavor::Gcc | LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => {}
}
}
fn add_post_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) {
add_link_args(&mut self.post_link_args, flavor, args);
}
+
+ fn update_from_cli(&mut self) {
+ self.linker_flavor = LinkerFlavor::from_cli(self.linker_flavor_json);
+ for (args, args_json) in [
+ (&mut self.pre_link_args, &self.pre_link_args_json),
+ (&mut self.late_link_args, &self.late_link_args_json),
+ (&mut self.late_link_args_dynamic, &self.late_link_args_dynamic_json),
+ (&mut self.late_link_args_static, &self.late_link_args_static_json),
+ (&mut self.post_link_args, &self.post_link_args_json),
+ ] {
+ *args = args_json
+ .iter()
+ .map(|(flavor, args)| (LinkerFlavor::from_cli(*flavor), args.clone()))
+ .collect();
+ }
+ }
+
+ fn update_to_cli(&mut self) {
+ self.linker_flavor_json = self.linker_flavor.to_cli();
+ for (args, args_json) in [
+ (&self.pre_link_args, &mut self.pre_link_args_json),
+ (&self.late_link_args, &mut self.late_link_args_json),
+ (&self.late_link_args_dynamic, &mut self.late_link_args_dynamic_json),
+ (&self.late_link_args_static, &mut self.late_link_args_static_json),
+ (&self.post_link_args, &mut self.post_link_args_json),
+ ] {
+ *args_json =
+ args.iter().map(|(flavor, args)| (flavor.to_cli(), args.clone())).collect();
+ }
+ }
}
impl Default for TargetOptions {
env: "".into(),
abi: "".into(),
vendor: "unknown".into(),
- linker_flavor: LinkerFlavor::Gcc,
linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()),
+ linker_flavor: LinkerFlavor::Gcc,
+ linker_flavor_json: LinkerFlavorCli::Gcc,
lld_flavor: LldFlavor::Ld,
- pre_link_args: LinkArgs::new(),
- post_link_args: LinkArgs::new(),
+ linker_is_gnu: true,
link_script: None,
asm_args: cvs![],
cpu: "generic".into(),
is_like_msvc: false,
is_like_wasm: false,
default_dwarf_version: 4,
- linker_is_gnu: true,
allows_weak_linkage: true,
has_rpath: false,
no_default_libraries: true,
pre_link_objects_self_contained: Default::default(),
post_link_objects_self_contained: Default::default(),
link_self_contained: LinkSelfContainedDefault::False,
+ pre_link_args: LinkArgs::new(),
+ pre_link_args_json: LinkArgsCli::new(),
late_link_args: LinkArgs::new(),
+ late_link_args_json: LinkArgsCli::new(),
late_link_args_dynamic: LinkArgs::new(),
+ late_link_args_dynamic_json: LinkArgsCli::new(),
late_link_args_static: LinkArgs::new(),
+ late_link_args_static_json: LinkArgsCli::new(),
+ post_link_args: LinkArgs::new(),
+ post_link_args_json: LinkArgsCli::new(),
link_env: cvs![],
link_env_remove: cvs![],
archive_format: "gnu".into(),
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
- ($key_name:ident, LinkerFlavor) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
- match LinkerFlavor::from_str(s) {
+ ($key_name:ident = $json_name:expr, LinkerFlavor) => ( {
+ let name = $json_name;
+ obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
+ match LinkerFlavorCli::from_str(s) {
Some(linker_flavor) => base.$key_name = linker_flavor,
_ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
- Use {}", s, LinkerFlavor::one_of()))),
+ Use {}", s, LinkerFlavorCli::one_of()))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
base.$key_name = args;
}
} );
- ($key_name:ident, link_args) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- if let Some(val) = obj.remove(&name) {
+ ($key_name:ident = $json_name:expr, link_args) => ( {
+ let name = $json_name;
+ if let Some(val) = obj.remove(name) {
let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
JSON object with fields per linker-flavor.", name))?;
- let mut args = LinkArgs::new();
+ let mut args = LinkArgsCli::new();
for (k, v) in obj {
- let flavor = LinkerFlavor::from_str(&k).ok_or_else(|| {
+ let flavor = LinkerFlavorCli::from_str(&k).ok_or_else(|| {
format!("{}: '{}' is not a valid value for linker-flavor. \
Use 'em', 'gcc', 'ld' or 'msvc'", name, k)
})?;
key!(env);
key!(abi);
key!(vendor);
- key!(linker_flavor, LinkerFlavor)?;
key!(linker, optional);
+ key!(linker_flavor_json = "linker-flavor", LinkerFlavor)?;
key!(lld_flavor, LldFlavor)?;
+ key!(linker_is_gnu, bool);
key!(pre_link_objects = "pre-link-objects", link_objects);
key!(post_link_objects = "post-link-objects", link_objects);
key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects);
key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects);
key!(link_self_contained = "crt-objects-fallback", link_self_contained)?;
- key!(pre_link_args, link_args);
- key!(late_link_args, link_args);
- key!(late_link_args_dynamic, link_args);
- key!(late_link_args_static, link_args);
- key!(post_link_args, link_args);
+ key!(pre_link_args_json = "pre-link-args", link_args);
+ key!(late_link_args_json = "late-link-args", link_args);
+ key!(late_link_args_dynamic_json = "late-link-args-dynamic", link_args);
+ key!(late_link_args_static_json = "late-link-args-static", link_args);
+ key!(post_link_args_json = "post-link-args", link_args);
key!(link_script, optional);
key!(link_env, env);
key!(link_env_remove, list);
key!(is_like_msvc, bool);
key!(is_like_wasm, bool);
key!(default_dwarf_version, u32);
- key!(linker_is_gnu, bool);
key!(allows_weak_linkage, bool);
key!(has_rpath, bool);
key!(no_default_libraries, bool);
// This can cause unfortunate ICEs later down the line.
return Err("may not set is_builtin for targets not built-in".into());
}
+ base.update_from_cli();
+
// Each field should have been read using `Json::remove` so any keys remaining are unused.
let remaining_keys = obj.keys();
Ok((
fn to_json(&self) -> Json {
let mut d = serde_json::Map::new();
let default: TargetOptions = Default::default();
+ let mut target = self.clone();
+ target.update_to_cli();
macro_rules! target_val {
($attr:ident) => {{
let name = (stringify!($attr)).replace("_", "-");
- d.insert(name, self.$attr.to_json());
+ d.insert(name, target.$attr.to_json());
}};
}
macro_rules! target_option_val {
($attr:ident) => {{
let name = (stringify!($attr)).replace("_", "-");
- if default.$attr != self.$attr {
- d.insert(name, self.$attr.to_json());
+ if default.$attr != target.$attr {
+ d.insert(name, target.$attr.to_json());
}
}};
- ($attr:ident, $key_name:expr) => {{
- let name = $key_name;
- if default.$attr != self.$attr {
- d.insert(name.into(), self.$attr.to_json());
+ ($attr:ident, $json_name:expr) => {{
+ let name = $json_name;
+ if default.$attr != target.$attr {
+ d.insert(name.into(), target.$attr.to_json());
}
}};
- (link_args - $attr:ident) => {{
- let name = (stringify!($attr)).replace("_", "-");
- if default.$attr != self.$attr {
- let obj = self
+ (link_args - $attr:ident, $json_name:expr) => {{
+ let name = $json_name;
+ if default.$attr != target.$attr {
+ let obj = target
.$attr
.iter()
.map(|(k, v)| (k.desc().to_string(), v.clone()))
.collect::<BTreeMap<_, _>>();
- d.insert(name, obj.to_json());
+ d.insert(name.to_string(), obj.to_json());
}
}};
(env - $attr:ident) => {{
let name = (stringify!($attr)).replace("_", "-");
- if default.$attr != self.$attr {
- let obj = self
+ if default.$attr != target.$attr {
+ let obj = target
.$attr
.iter()
.map(|&(ref k, ref v)| format!("{k}={v}"))
target_option_val!(env);
target_option_val!(abi);
target_option_val!(vendor);
- target_option_val!(linker_flavor);
target_option_val!(linker);
+ target_option_val!(linker_flavor_json, "linker-flavor");
target_option_val!(lld_flavor);
+ target_option_val!(linker_is_gnu);
target_option_val!(pre_link_objects);
target_option_val!(post_link_objects);
target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback");
target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback");
target_option_val!(link_self_contained, "crt-objects-fallback");
- target_option_val!(link_args - pre_link_args);
- target_option_val!(link_args - late_link_args);
- target_option_val!(link_args - late_link_args_dynamic);
- target_option_val!(link_args - late_link_args_static);
- target_option_val!(link_args - post_link_args);
+ target_option_val!(link_args - pre_link_args_json, "pre-link-args");
+ target_option_val!(link_args - late_link_args_json, "late-link-args");
+ target_option_val!(link_args - late_link_args_dynamic_json, "late-link-args-dynamic");
+ target_option_val!(link_args - late_link_args_static_json, "late-link-args-static");
+ target_option_val!(link_args - post_link_args_json, "post-link-args");
target_option_val!(link_script);
target_option_val!(env - link_env);
target_option_val!(link_env_remove);
target_option_val!(is_like_msvc);
target_option_val!(is_like_wasm);
target_option_val!(default_dwarf_version);
- target_option_val!(linker_is_gnu);
target_option_val!(allows_weak_linkage);
target_option_val!(has_rpath);
target_option_val!(no_default_libraries);
options: TargetOptions {
os: "cuda".into(),
vendor: "nvidia".into(),
- linker_flavor: LinkerFlavor::PtxLinker,
+ linker_flavor: LinkerFlavor::Ptx,
// The linker can be installed from `crates.io`.
linker: Some("rust-ptx-linker".into()),
linker_is_gnu: false,
use std::assert_matches::assert_matches;
// Test target self-consistency and JSON encoding/decoding roundtrip.
-pub(super) fn test_target(target: Target, triple: &str) {
+pub(super) fn test_target(mut target: Target, triple: &str) {
+ let recycled_target = Target::from_json(target.to_json()).map(|(j, _)| j);
+ target.update_to_cli();
target.check_consistency(triple);
- assert_eq!(Target::from_json(target.to_json()).map(|(j, _)| j), Ok(target));
+ assert_eq!(recycled_target, Ok(target));
}
impl Target {
assert_eq!(self.is_like_osx, matches!(self.lld_flavor, LldFlavor::Ld64));
assert_eq!(self.is_like_msvc, matches!(self.lld_flavor, LldFlavor::Link));
assert_eq!(self.is_like_wasm, matches!(self.lld_flavor, LldFlavor::Wasm));
- assert_eq!(self.os == "l4re", matches!(self.linker_flavor, LinkerFlavor::L4Bender));
- assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::Em));
- assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::BpfLinker));
- assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::PtxLinker));
+ assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::EmCc));
+ assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::Bpf));
+ assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::Ptx));
for args in [
&self.pre_link_args,
LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc
)
}
- (LinkerFlavor::L4Bender, LldFlavor::Ld) => {
- assert_matches!(flavor, LinkerFlavor::L4Bender)
+ (LinkerFlavor::EmCc, LldFlavor::Wasm) => {
+ assert_matches!(flavor, LinkerFlavor::EmCc)
}
- (LinkerFlavor::Em, LldFlavor::Wasm) => {
- assert_matches!(flavor, LinkerFlavor::Em)
+ (LinkerFlavor::Bpf, LldFlavor::Ld) => {
+ assert_matches!(flavor, LinkerFlavor::Bpf)
}
- (LinkerFlavor::BpfLinker, LldFlavor::Ld) => {
- assert_matches!(flavor, LinkerFlavor::BpfLinker)
- }
- (LinkerFlavor::PtxLinker, LldFlavor::Ld) => {
- assert_matches!(flavor, LinkerFlavor::PtxLinker)
+ (LinkerFlavor::Ptx, LldFlavor::Ld) => {
+ assert_matches!(flavor, LinkerFlavor::Ptx)
}
flavors => unreachable!("unexpected flavor combination: {:?}", flavors),
}
// Reset flags for non-Em flavors back to empty to satisfy sanity checking tests.
let pre_link_args = LinkArgs::new();
let post_link_args = TargetOptions::link_args(
- LinkerFlavor::Em,
+ LinkerFlavor::EmCc,
&["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"],
);
let opts = TargetOptions {
os: "emscripten".into(),
- linker_flavor: LinkerFlavor::Em,
+ linker_flavor: LinkerFlavor::EmCc,
// emcc emits two files - a .js file to instantiate the wasm and supply platform
// functionality, and a .wasm file.
exe_suffix: ".js".into(),
+use crate::errors::AutoDerefReachedRecursionLimit;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{self, TraitEngine};
-use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt};
Limit(0) => Limit(2),
limit => limit * 2,
};
- struct_span_err!(
- tcx.sess,
+ tcx.sess.emit_err(AutoDerefReachedRecursionLimit {
span,
- E0055,
- "reached the recursion limit while auto-dereferencing `{:?}`",
- ty
- )
- .span_label(span, "deref recursion limit reached")
- .help(&format!(
- "consider increasing the recursion limit by adding a \
- `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
+ ty,
suggested_limit,
- tcx.crate_name(LOCAL_CRATE),
- ))
- .emit();
+ crate_name: tcx.crate_name(LOCAL_CRATE),
+ });
}
--- /dev/null
+use rustc_errors::{fluent, ErrorGuaranteed};
+use rustc_macros::SessionDiagnostic;
+use rustc_middle::ty::{PolyTraitRef, Ty, Unevaluated};
+use rustc_session::{parse::ParseSess, Limit, SessionDiagnostic};
+use rustc_span::{Span, Symbol};
+
+#[derive(SessionDiagnostic)]
+#[diag(trait_selection::dump_vtable_entries)]
+pub struct DumpVTableEntries<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub trait_ref: PolyTraitRef<'a>,
+ pub entries: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(trait_selection::unable_to_construct_constant_value)]
+pub struct UnableToConstructConstantValue<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub unevaluated: Unevaluated<'a>,
+}
+
+#[derive(SessionDiagnostic)]
+#[help]
+#[diag(trait_selection::auto_deref_reached_recursion_limit, code = "E0055")]
+pub struct AutoDerefReachedRecursionLimit<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub ty: Ty<'a>,
+ pub suggested_limit: Limit,
+ pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(trait_selection::empty_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+pub struct EmptyOnClauseInOnUnimplemented {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(trait_selection::invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+pub struct InvalidOnClauseInOnUnimplemented {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(trait_selection::no_value_in_rustc_on_unimplemented, code = "E0232")]
+#[note]
+pub struct NoValueInOnUnimplemented {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+pub struct NegativePositiveConflict<'a> {
+ pub impl_span: Span,
+ pub trait_desc: &'a str,
+ pub self_desc: &'a Option<String>,
+ pub negative_impl_span: Result<Span, Symbol>,
+ pub positive_impl_span: Result<Span, Symbol>,
+}
+
+impl SessionDiagnostic<'_> for NegativePositiveConflict<'_> {
+ fn into_diagnostic(
+ self,
+ sess: &ParseSess,
+ ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag = sess.struct_err(fluent::trait_selection::negative_positive_conflict);
+ diag.set_arg("trait_desc", self.trait_desc);
+ diag.set_arg(
+ "self_desc",
+ self.self_desc.clone().map_or_else(|| String::from("none"), |ty| ty),
+ );
+ diag.set_span(self.impl_span);
+ diag.code(rustc_errors::error_code!(E0751));
+ match self.negative_impl_span {
+ Ok(span) => {
+ diag.span_label(span, fluent::trait_selection::negative_implementation_here);
+ }
+ Err(cname) => {
+ diag.note(fluent::trait_selection::negative_implementation_in_crate);
+ diag.set_arg("negative_impl_cname", cname.to_string());
+ }
+ }
+ match self.positive_impl_span {
+ Ok(span) => {
+ diag.span_label(span, fluent::trait_selection::positive_implementation_here);
+ }
+ Err(cname) => {
+ diag.note(fluent::trait_selection::positive_implementation_in_crate);
+ diag.set_arg("positive_impl_cname", cname.to_string());
+ }
+ }
+ diag
+ }
+}
span: Span,
) -> bool;
+ fn type_is_sized_modulo_regions(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ span: Span,
+ ) -> bool;
+
fn partially_normalize_associated_types_in<T>(
&self,
cause: ObligationCause<'tcx>,
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
}
+ fn type_is_sized_modulo_regions(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ span: Span,
+ ) -> bool {
+ let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
+ traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span)
+ }
+
/// Normalizes associated types in `value`, potentially returning
/// new obligations that must further be processed.
fn partially_normalize_associated_types_in<T>(
extern crate smallvec;
pub mod autoderef;
+pub mod errors;
pub mod infer;
pub mod traits;
use super::*;
+use crate::errors::UnableToConstructConstantValue;
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxt;
use crate::traits::project::ProjectAndUnifyResult;
Ok(None) => {
let tcx = self.tcx;
let def_id = unevaluated.def.did;
- let reported = tcx.sess.struct_span_err(tcx.def_span(def_id), &format!("unable to construct a constant value for the unevaluated constant {:?}", unevaluated)).emit();
-
+ let reported =
+ tcx.sess.emit_err(UnableToConstructConstantValue {
+ span: tcx.def_span(def_id),
+ unevaluated,
+ });
Err(ErrorHandled::Reported(reported))
}
Err(err) => Err(err),
/// obligations *could be* resolved if we wanted to.
///
/// This also expects that `trait_ref` is fully normalized.
-#[instrument(level = "debug", skip(tcx))]
pub fn codegen_fulfill_obligation<'tcx>(
tcx: TyCtxt<'tcx>,
(param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
// (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- debug!("Cache miss: {trait_ref:?} => {impl_source:?}");
Ok(&*tcx.arena.alloc(impl_source))
})
}
message,
label,
note,
- enclosing_scope,
+ parent_label,
append_const_msg,
} = self.on_unimplemented_note(trait_ref, &obligation);
let have_alt_message = message.is_some() || label.is_some();
{
"consider using `()`, or a `Result`".to_owned()
} else {
- format!(
- "{}the trait `{}` is not implemented for `{}`",
- pre_message,
- trait_predicate.print_modifiers_and_trait_path(),
- trait_ref.skip_binder().self_ty(),
- )
+ let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
+ ty::FnDef(_, _) => Some("fn item"),
+ ty::Closure(_, _) => Some("closure"),
+ _ => None,
+ };
+
+ match ty_desc {
+ Some(desc) => format!(
+ "{}the trait `{}` is not implemented for {} `{}`",
+ pre_message,
+ trait_predicate.print_modifiers_and_trait_path(),
+ desc,
+ trait_ref.skip_binder().self_ty(),
+ ),
+ None => format!(
+ "{}the trait `{}` is not implemented for `{}`",
+ pre_message,
+ trait_predicate.print_modifiers_and_trait_path(),
+ trait_ref.skip_binder().self_ty(),
+ ),
+ }
};
if self.suggest_add_reference_to_arg(
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
err.note(s.as_str());
}
- if let Some(ref s) = enclosing_scope {
+ if let Some(ref s) = parent_label {
let body = tcx
.hir()
.opt_local_def_id(obligation.cause.body_id)
hir_id: obligation.cause.body_id,
})
});
-
- let enclosing_scope_span =
- tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(body));
-
- err.span_label(enclosing_scope_span, s);
+ err.span_label(tcx.def_span(body), s);
}
self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref);
return false;
}
if candidates.len() == 1 {
+ let ty_desc = match candidates[0].self_ty().kind() {
+ ty::FnPtr(_) => Some("fn pointer"),
+ _ => None,
+ };
+ let the_desc = match ty_desc {
+ Some(desc) => format!(" implemented for {} `", desc),
+ None => " implemented for `".to_string(),
+ };
err.highlighted_help(vec![
(
format!("the trait `{}` ", candidates[0].print_only_trait_path()),
Style::NoStyle,
),
("is".to_string(), Style::Highlight),
- (" implemented for `".to_string(), Style::NoStyle),
+ (the_desc, Style::NoStyle),
(candidates[0].self_ty().to_string(), Style::Highlight),
("`".to_string(), Style::NoStyle),
]);
let predicate = self.resolve_vars_if_possible(obligation.predicate);
let span = obligation.cause.span;
- debug!(?predicate, obligation.cause.code = tracing::field::debug(&obligation.cause.code()));
+ debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
// Ambiguity errors are often caused as fallout from earlier errors.
// We ignore them if this `infcx` is tainted in some cases below.
&& let [
..,
trait_path_segment @ hir::PathSegment {
- res: Some(rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id)),
+ res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id),
..
},
hir::PathSegment {
ident: assoc_item_name,
- res: Some(rustc_hir::def::Res::Def(_, item_id)),
+ res: rustc_hir::def::Res::Def(_, item_id),
..
}
] = path.segments
// Get the local name of this closure. This can be inaccurate because
// of the possibility of reassignment, but this should be good enough.
match &kind {
- hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, None) => {
+ hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, ident, None) => {
Some(ident.name)
}
_ => {
/// `SomeTrait` or a where-clause that lets us unify `$0` with
/// something concrete. If this fails, we'll unify `$0` with
/// `projection_ty` again.
- #[tracing::instrument(level = "debug", skip(self, infcx, param_env, cause))]
+ #[instrument(level = "debug", skip(self, infcx, param_env, cause))]
fn normalize_projection_type(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
mod util;
pub mod wf;
+use crate::errors::DumpVTableEntries;
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::error_reporting::InferCtxtExt as _;
trait_ref: ty::PolyTraitRef<'tcx>,
entries: &[VtblEntry<'tcx>],
) {
- let msg = format!("vtable entries for `{}`: {:#?}", trait_ref, entries);
- tcx.sess.struct_span_err(sp, &msg).emit();
+ tcx.sess.emit_err(DumpVTableEntries {
+ span: sp,
+ trait_ref,
+ entries: format!("{:#?}", entries),
+ });
}
fn own_existential_vtable_entries<'tcx>(
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
+use crate::errors::{
+ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
+};
+
#[derive(Clone, Debug)]
pub struct OnUnimplementedFormatString(Symbol);
pub message: Option<OnUnimplementedFormatString>,
pub label: Option<OnUnimplementedFormatString>,
pub note: Option<OnUnimplementedFormatString>,
- pub enclosing_scope: Option<OnUnimplementedFormatString>,
+ pub parent_label: Option<OnUnimplementedFormatString>,
pub append_const_msg: Option<Option<Symbol>>,
}
pub message: Option<String>,
pub label: Option<String>,
pub note: Option<String>,
- pub enclosing_scope: Option<String>,
+ pub parent_label: Option<String>,
/// Append a message for `~const Trait` errors. `None` means not requested and
/// should fallback to a generic message, `Some(None)` suggests using the default
/// appended message, `Some(Some(s))` suggests use the `s` message instead of the
pub append_const_msg: Option<Option<Symbol>>,
}
-fn parse_error(
- tcx: TyCtxt<'_>,
- span: Span,
- message: &str,
- label: &str,
- note: Option<&str>,
-) -> ErrorGuaranteed {
- let mut diag = struct_span_err!(tcx.sess, span, E0232, "{}", message);
- diag.span_label(span, label);
- if let Some(note) = note {
- diag.note(note);
- }
- diag.emit()
-}
-
impl<'tcx> OnUnimplementedDirective {
fn parse(
tcx: TyCtxt<'tcx>,
} else {
let cond = item_iter
.next()
- .ok_or_else(|| {
- parse_error(
- tcx,
- span,
- "empty `on`-clause in `#[rustc_on_unimplemented]`",
- "empty on-clause here",
- None,
- )
- })?
+ .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))?
.meta_item()
- .ok_or_else(|| {
- parse_error(
- tcx,
- span,
- "invalid `on`-clause in `#[rustc_on_unimplemented]`",
- "invalid on-clause here",
- None,
- )
- })?;
+ .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
if let Some(value) = cfg.value && let Err(guar) = parse_value(value) {
errored = Some(guar);
let mut message = None;
let mut label = None;
let mut note = None;
- let mut enclosing_scope = None;
+ let mut parent_label = None;
let mut subcommands = vec![];
let mut append_const_msg = None;
note = parse_value(note_)?;
continue;
}
- } else if item.has_name(sym::enclosing_scope) && enclosing_scope.is_none() {
- if let Some(enclosing_scope_) = item.value_str() {
- enclosing_scope = parse_value(enclosing_scope_)?;
+ } else if item.has_name(sym::parent_label) && parent_label.is_none() {
+ if let Some(parent_label_) = item.value_str() {
+ parent_label = parse_value(parent_label_)?;
continue;
}
} else if item.has_name(sym::on)
}
// nothing found
- parse_error(
- tcx,
- item.span(),
- "this attribute must have a valid value",
- "expected value here",
- Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#),
- );
+ tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
}
if let Some(reported) = errored {
message,
label,
note,
- enclosing_scope,
+ parent_label,
append_const_msg,
})
}
attr.span,
)?),
note: None,
- enclosing_scope: None,
+ parent_label: None,
append_const_msg: None,
}))
} else {
let mut message = None;
let mut label = None;
let mut note = None;
- let mut enclosing_scope = None;
+ let mut parent_label = None;
let mut append_const_msg = None;
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
note = Some(note_.clone());
}
- if let Some(ref enclosing_scope_) = command.enclosing_scope {
- enclosing_scope = Some(enclosing_scope_.clone());
+ if let Some(ref parent_label_) = command.parent_label {
+ parent_label = Some(parent_label_.clone());
}
append_const_msg = command.append_const_msg;
label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
- enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
+ parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
append_const_msg,
}
}
/// If successful, this may result in additional obligations.
///
/// See [poly_project_and_unify_type] for an explanation of the return value.
-#[tracing::instrument(level = "debug", skip(selcx))]
+#[instrument(level = "debug", skip(selcx))]
fn project_and_unify_type<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionObligation<'tcx>,
///
/// IMPORTANT:
/// - `obligation` must be fully normalized
-#[tracing::instrument(level = "info", skip(selcx))]
+#[instrument(level = "info", skip(selcx))]
fn project<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
);
}
-#[tracing::instrument(
+#[instrument(
level = "debug",
skip(selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates)
)]
}
}
-#[tracing::instrument(level = "debug", skip(selcx, obligation, candidate_set))]
+#[instrument(level = "debug", skip(selcx, obligation, candidate_set))]
fn assemble_candidates_from_impls<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack};
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
pub(super) fn candidate_from_obligation<'o>(
&mut self,
stack: &TraitObligationStack<'o, 'tcx>,
if let Some(c) =
self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred)
{
- debug!(candidate = ?c, "CACHE HIT");
+ debug!("CACHE HIT");
return c;
}
let (candidate, dep_node) =
self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
- debug!(?candidate, "CACHE MISS");
+ debug!("CACHE MISS");
self.insert_candidate_cache(
stack.obligation.param_env,
cache_fresh_trait_pred,
Ok(candidates)
}
- #[tracing::instrument(level = "debug", skip(self, candidates))]
+ #[instrument(level = "debug", skip(self, candidates))]
fn assemble_candidates_from_projected_tys(
&mut self,
obligation: &TraitObligation<'tcx>,
/// supplied to find out whether it is listed among them.
///
/// Never affects the inference environment.
- #[tracing::instrument(level = "debug", skip(self, stack, candidates))]
+ #[instrument(level = "debug", skip(self, stack, candidates))]
fn assemble_candidates_from_caller_bounds<'o>(
&mut self,
stack: &TraitObligationStack<'o, 'tcx>,
};
}
- #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+ #[instrument(level = "debug", skip(self, obligation, candidates))]
fn assemble_candidates_for_transmutability(
&mut self,
obligation: &TraitObligation<'tcx>,
candidates.vec.push(TransmutabilityCandidate);
}
- #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+ #[instrument(level = "debug", skip(self, obligation, candidates))]
fn assemble_candidates_for_trait_alias(
&mut self,
obligation: &TraitObligation<'tcx>,
/// Assembles the trait which are built-in to the language itself:
/// `Copy`, `Clone` and `Sized`.
- #[tracing::instrument(level = "debug", skip(self, candidates))]
+ #[instrument(level = "debug", skip(self, candidates))]
fn assemble_builtin_bound_candidates(
&mut self,
conditions: BuiltinImplConditions<'tcx>,
let predicate = obligation.predicate;
let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i));
- let bool_at = |i| {
- predicate
- .skip_binder()
- .trait_ref
- .substs
- .const_at(i)
- .try_eval_bool(self.tcx(), obligation.param_env)
- .unwrap_or(true)
- };
+ let const_at = |i| predicate.skip_binder().trait_ref.substs.const_at(i);
let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
- src: p.trait_ref.substs.type_at(1),
dst: p.trait_ref.substs.type_at(0),
+ src: p.trait_ref.substs.type_at(1),
});
let scope = type_at(2).skip_binder();
- let assume = rustc_transmute::Assume {
- alignment: bool_at(3),
- lifetimes: bool_at(4),
- validity: bool_at(5),
- visibility: bool_at(6),
- };
+ let assume =
+ rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, const_at(3));
let cause = obligation.cause.clone();
/// Attempts to satisfy the obligation. If successful, this will affect the surrounding
/// type environment by performing unification.
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
pub fn select(
&mut self,
obligation: &TraitObligation<'tcx>,
Err(SelectionError::Overflow(OverflowError::Canonical))
}
Err(e) => Err(e),
- Ok(candidate) => {
- debug!(?candidate, "confirmed");
- Ok(Some(candidate))
- }
+ Ok(candidate) => Ok(Some(candidate)),
}
}
level = "debug",
skip(self, previous_stack),
fields(previous_stack = ?previous_stack.head())
+ ret,
)]
fn evaluate_predicate_recursively<'o>(
&mut self,
None => self.check_recursion_limit(&obligation, &obligation)?,
}
- let result = ensure_sufficient_stack(|| {
+ ensure_sufficient_stack(|| {
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(t) => {
bug!("TypeWellFormedFromEnv is only used for chalk")
}
}
- });
-
- debug!("finished: {:?} from {:?}", result, obligation);
-
- result
+ })
}
- #[instrument(skip(self, previous_stack), level = "debug")]
+ #[instrument(skip(self, previous_stack), level = "debug", ret)]
fn evaluate_trait_predicate_recursively<'o>(
&mut self,
previous_stack: TraitObligationStackList<'o, 'tcx>,
// If a trait predicate is in the (local or global) evaluation cache,
// then we know it holds without cycles.
if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) {
- debug!(?result, "CACHE HIT");
+ debug!("CACHE HIT");
return Ok(result);
}
if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) {
- debug!(?result, "PROVISIONAL CACHE HIT");
+ debug!("PROVISIONAL CACHE HIT");
stack.update_reached_depth(result.reached_depth);
return Ok(result.result);
}
let reached_depth = stack.reached_depth.get();
if reached_depth >= stack.depth {
- debug!(?result, "CACHE MISS");
+ debug!("CACHE MISS");
self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result);
stack.cache().on_completion(stack.dfn);
} else {
- debug!(?result, "PROVISIONAL");
+ debug!("PROVISIONAL");
debug!(
"caching provisionally because {:?} \
is a cycle participant (at depth {}, reached depth {})",
#[instrument(
level = "debug",
skip(self, stack),
- fields(depth = stack.obligation.recursion_depth)
+ fields(depth = stack.obligation.recursion_depth),
+ ret
)]
fn evaluate_candidate<'o>(
&mut self,
result = result.max(EvaluatedToOkModuloRegions);
}
- debug!(?result);
Ok(result)
}
/// a projection, look at the bounds of `T::Bar`, see if we can find a
/// `Baz` bound. We return indexes into the list returned by
/// `tcx.item_bounds` for any applicable bounds.
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
fn match_projection_obligation_against_definition_bounds(
&mut self,
obligation: &TraitObligation<'tcx>,
// unnecessary ambiguity.
let mut distinct_normalized_bounds = FxHashSet::default();
- let matching_bounds = bounds
+ bounds
.iter()
.enumerate()
.filter_map(|(idx, bound)| {
}
None
})
- .collect();
-
- debug!(?matching_bounds);
- matching_bounds
+ .collect()
}
/// Equates the trait in `obligation` with trait bound. If the two traits
}
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
fn match_impl(
&mut self,
impl_def_id: DefId,
.at(&cause, obligation.param_env)
.define_opaque_types(false)
.eq(placeholder_obligation_trait_ref, impl_trait_ref)
- .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
+ .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{e}`"))?;
nested_obligations.extend(obligations);
if !self.intercrate
&& self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
{
- debug!("match_impl: reservation impls only apply in intercrate mode");
+ debug!("reservation impls only apply in intercrate mode");
return Err(());
}
- debug!(?impl_substs, ?nested_obligations, "match_impl: success");
Ok(Normalized { value: impl_substs, obligations: nested_obligations })
}
/// impl or trait. The obligations are substituted and fully
/// normalized. This is used when confirming an impl or default
/// impl.
- #[tracing::instrument(level = "debug", skip(self, cause, param_env))]
+ #[instrument(level = "debug", skip(self, cause, param_env))]
fn impl_or_trait_obligations(
&mut self,
cause: &ObligationCause<'tcx>,
pub mod specialization_graph;
use specialization_graph::GraphExt;
+use crate::errors::NegativePositiveConflict;
use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
positive_impl_def_id: DefId,
sg: &mut specialization_graph::Graph,
) {
- let impl_span = tcx.def_span(local_impl_def_id);
-
- let mut err = struct_span_err!(
- tcx.sess,
- impl_span,
- E0751,
- "found both positive and negative implementation of trait `{}`{}:",
- overlap.trait_desc,
- overlap.self_desc.clone().map_or_else(String::new, |ty| format!(" for type `{}`", ty))
- );
-
- match tcx.span_of_impl(negative_impl_def_id) {
- Ok(span) => {
- err.span_label(span, "negative implementation here");
- }
- Err(cname) => {
- err.note(&format!("negative implementation in crate `{}`", cname));
- }
- }
-
- match tcx.span_of_impl(positive_impl_def_id) {
- Ok(span) => {
- err.span_label(span, "positive implementation here");
- }
- Err(cname) => {
- err.note(&format!("positive implementation in crate `{}`", cname));
- }
- }
-
+ let mut err = tcx.sess.create_err(NegativePositiveConflict {
+ impl_span: tcx.def_span(local_impl_def_id),
+ trait_desc: &overlap.trait_desc,
+ self_desc: &overlap.self_desc,
+ negative_impl_span: tcx.span_of_impl(negative_impl_def_id),
+ positive_impl_span: tcx.span_of_impl(positive_impl_def_id),
+ });
sg.has_errored = Some(err.emit());
}
///
/// Requires that trait definitions have been processed so that we can
/// elaborate predicates and walk supertraits.
-#[instrument(skip(tcx, predicates), level = "debug")]
+#[instrument(skip(tcx, predicates), level = "debug", ret)]
pub(crate) fn required_region_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
erased_self_ty: Ty<'tcx>,
[dependencies]
tracing = "0.1"
-rustc_data_structures = { path = "../rustc_data_structures", optional = true}
+rustc_data_structures = { path = "../rustc_data_structures"}
+rustc_hir = { path = "../rustc_hir", optional = true}
rustc_infer = { path = "../rustc_infer", optional = true}
rustc_macros = { path = "../rustc_macros", optional = true}
rustc_middle = { path = "../rustc_middle", optional = true}
[features]
rustc = [
"rustc_middle",
- "rustc_data_structures",
+ "rustc_hir",
"rustc_infer",
"rustc_macros",
"rustc_span",
}
#[instrument(level = "debug")]
- #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
pub(crate) fn from_nfa(nfa: Nfa<R>) -> Self {
let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa;
let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions;
- // the iteration order doesn't matter
- #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
for (source, transition) in other.transitions {
let fix_state = |state| if state == other.start { self.accepting } else { state };
let entry = transitions.entry(fix_state(source)).or_default();
let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions.clone();
- // the iteration order doesn't matter
- #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
for (&(mut source), transition) in other.transitions.iter() {
// if source is starting state of `other`, replace with starting state of `self`
if source == other.start {
let entry = transitions.entry(source).or_default();
for (edge, destinations) in transition {
let entry = entry.entry(edge.clone()).or_default();
- // the iteration order doesn't matter
- #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
for &(mut destination) in destinations {
// if dest is accepting state of `other`, replace with accepting state of `self`
if destination == other.accepting {
tcx,
)?,
AdtKind::Enum => {
- tracing::trace!(?adt_def, "treeifying enum");
+ trace!(?adt_def, "treeifying enum");
let mut tree = Tree::uninhabited();
for (idx, discr) in adt_def.discriminants(tcx) {
let clamp =
|align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap();
- let variant_span = tracing::trace_span!(
+ let variant_span = trace_span!(
"treeifying variant",
min_align = ?min_align,
max_align = ?max_align,
// The layout of the variant is prefixed by the discriminant, if any.
if let Some(discr) = discr {
- tracing::trace!(?discr, "treeifying discriminant");
+ trace!(?discr, "treeifying discriminant");
let discr_layout = alloc::Layout::from_size_align(
layout_summary.discriminant_size,
clamp(layout_summary.discriminant_align),
)
.unwrap();
- tracing::trace!(?discr_layout, "computed discriminant layout");
+ trace!(?discr_layout, "computed discriminant layout");
variant_layout = variant_layout.extend(discr_layout).unwrap().0;
tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size));
}
// Next come fields.
- let fields_span = tracing::trace_span!("treeifying fields").entered();
+ let fields_span = trace_span!("treeifying fields").entered();
for field_def in variant_def.fields.iter() {
let field_ty = field_def.ty(tcx, substs_ref);
- let _span = tracing::trace_span!("treeifying field", field = ?field_ty).entered();
+ let _span = trace_span!("treeifying field", field = ?field_ty).entered();
// begin with the field's visibility
tree = tree.then(Self::def(Def::Field(field_def)));
drop(fields_span);
// finally: padding
- let padding_span = tracing::trace_span!("adding trailing padding").entered();
+ let padding_span = trace_span!("adding trailing padding").entered();
let padding_needed = layout_summary.total_size - variant_layout.size();
if padding_needed > 0 {
tree = tree.then(Self::padding(padding_needed));
layout.align().abi.bytes().try_into().unwrap(),
)
.unwrap();
- tracing::trace!(?ty, ?layout, "computed layout for type");
+ trace!(?ty, ?layout, "computed layout for type");
Ok(layout)
}
}
#[macro_use]
extern crate tracing;
-#[cfg(feature = "rustc")]
-pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set};
-
-#[cfg(not(feature = "rustc"))]
-pub(crate) use std::collections::{HashMap as Map, HashSet as Set};
+pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
pub(crate) mod layout;
pub(crate) mod maybe_transmutable;
pub struct Assume {
pub alignment: bool,
pub lifetimes: bool,
+ pub safety: bool,
pub validity: bool,
- pub visibility: bool,
}
/// The type encodes answers to the question: "Are these types transmutable?"
#[cfg(feature = "rustc")]
mod rustc {
+ use super::*;
+
+ use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::InferCtxt;
use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::Binder;
+ use rustc_middle::ty::Const;
+ use rustc_middle::ty::ParamEnv;
use rustc_middle::ty::Ty;
+ use rustc_middle::ty::TyCtxt;
/// The source and destination types of a transmutation.
#[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)]
.answer()
}
}
+
+ impl Assume {
+ /// Constructs an `Assume` from a given const-`Assume`.
+ pub fn from_const<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ c: Const<'tcx>,
+ ) -> Self {
+ use rustc_middle::ty::ScalarInt;
+ use rustc_middle::ty::TypeVisitable;
+ use rustc_span::symbol::sym;
+
+ let c = c.eval(tcx, param_env);
+
+ if let Some(err) = c.error_reported() {
+ return Self { alignment: true, lifetimes: true, safety: true, validity: true };
+ }
+
+ let adt_def = c.ty().ty_adt_def().expect("The given `Const` must be an ADT.");
+
+ assert_eq!(
+ tcx.require_lang_item(LangItem::TransmuteOpts, None),
+ adt_def.did(),
+ "The given `Const` was not marked with the `{}` lang item.",
+ LangItem::TransmuteOpts.name(),
+ );
+
+ let variant = adt_def.non_enum_variant();
+ let fields = c.to_valtree().unwrap_branch();
+
+ let get_field = |name| {
+ let (field_idx, _) = variant
+ .fields
+ .iter()
+ .enumerate()
+ .find(|(_, field_def)| name == field_def.name)
+ .expect(&format!("There were no fields named `{name}`."));
+ fields[field_idx].unwrap_leaf() == ScalarInt::TRUE
+ };
+
+ Self {
+ alignment: get_field(sym::alignment),
+ lifetimes: get_field(sym::lifetimes),
+ safety: get_field(sym::safety),
+ validity: get_field(sym::validity),
+ }
+ }
+ }
}
#[cfg(feature = "rustc")]
#[inline(always)]
#[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
- let assume_visibility = self.assume.visibility;
+ let assume_visibility = self.assume.safety;
let query_or_answer = self.map_layouts(|src, dst, scope, context| {
// Remove all `Def` nodes from `src`, without checking their visibility.
let src = src.prune(&|def| true);
- tracing::trace!(?src, "pruned src");
+ trace!(?src, "pruned src");
// Remove all `Def` nodes from `dst`, additionally...
let dst = if assume_visibility {
dst.prune(&|def| context.is_accessible_from(def, scope))
};
- tracing::trace!(?dst, "pruned dst");
+ trace!(?dst, "pruned dst");
// Convert `src` from a tree-based representation to an NFA-based representation.
// If the conversion fails because `src` is uninhabited, conclude that the transmutation
false
};
- tracing::trace!(?ret, "ret");
+ trace!(?ret, "ret");
ret
}
layout::Tree::<Def, !>::bool(),
layout::Tree::<Def, !>::bool(),
(),
- crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
+ crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false },
UltraMinimal,
)
.answer();
layout::Dfa::<!>::bool(),
layout::Dfa::<!>::bool(),
(),
- crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
+ crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false },
UltraMinimal,
)
.answer();
return true;
}
- match pat.kind.as_ref() {
+ match pat.kind {
thir::PatKind::Constant { value } => value.has_param_types_or_consts(),
- thir::PatKind::Range(thir::PatRange { lo, hi, .. }) => {
+ thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => {
lo.has_param_types_or_consts() || hi.has_param_types_or_consts()
}
_ => false,
use std::collections::BTreeMap;
use std::ops::ControlFlow;
-use tracing::debug;
-
// FIXME(#86795): `BoundVarsCollector` here should **NOT** be used
// outside of `resolve_associated_item`. It's just to address #64494,
// #83765, and #85848 which are creating bound types/regions that lose
}
/// 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) {
}
/// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead.
-#[instrument(level = "debug", skip(tcx))]
pub fn conservative_is_privately_uninhabited_raw<'tcx>(
tcx: TyCtxt<'tcx>,
param_env_and: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
multispan.push_span_label(span_late, note);
tcx.struct_span_lint_hir(
LATE_BOUND_LIFETIME_ARGUMENTS,
- args.args[0].id(),
+ args.args[0].hir_id(),
multispan,
|lint| {
lint.build(msg).emit();
/// instantiated with some generic arguments providing `'a` explicitly,
/// we taint those arguments with `ExplicitLateBound::Yes` so that we
/// can provide an appropriate diagnostic later.
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ExplicitLateBound {
Yes,
No,
/// A marker denoting that the generic arguments that were
/// provided did not match the respective generic parameters.
-#[derive(Clone, Default)]
+#[derive(Clone, Default, Debug)]
pub struct GenericArgCountMismatch {
/// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`).
pub reported: Option<ErrorGuaranteed>,
/// Decorates the result of a generic argument count mismatch
/// check with whether explicit late bounds were provided.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct GenericArgCountResult {
pub explicit_late_bound: ExplicitLateBound,
pub correct: Result<(), GenericArgCountMismatch>,
}
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
pub fn ast_region_to_region(
&self,
lifetime: &hir::Lifetime,
let tcx = self.tcx();
let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id));
- let r = match tcx.named_region(lifetime.hir_id) {
+ match tcx.named_region(lifetime.hir_id) {
Some(rl::Region::Static) => tcx.lifetimes.re_static,
Some(rl::Region::LateBound(debruijn, index, def_id)) => {
tcx.lifetimes.re_static
})
}
- };
- debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r);
- r
+ }
}
/// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
/// `[Vec<u8>, u8]` and `generic_args` are the arguments for the associated
/// type itself: `['a]`. The returned `SubstsRef` concatenates these two
/// lists: `[Vec<u8>, u8, 'a]`.
- #[tracing::instrument(level = "debug", skip(self, span))]
+ #[instrument(level = "debug", skip(self, span), ret)]
fn create_substs_for_ast_path<'a>(
&self,
span: Span,
if has_default {
tcx.check_optional_stability(
param.def_id,
- Some(arg.id()),
+ Some(arg.hir_id()),
arg.span(),
None,
AllowUnstable::No,
&mut substs_ctx,
);
- debug!(
- "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}",
- generics, self_ty, substs
- );
-
(substs, arg_count)
}
/// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be
/// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
/// however.
- #[tracing::instrument(level = "debug", skip(self, span, constness, bounds, speculative))]
+ #[instrument(level = "debug", skip(self, span, constness, bounds, speculative))]
pub(crate) fn instantiate_poly_trait_ref(
&self,
trait_ref: &hir::TraitRef<'_>,
ty::TraitRef::new(trait_def_id, substs)
}
- #[tracing::instrument(level = "debug", skip(self, span))]
+ #[instrument(level = "debug", skip(self, span))]
fn create_substs_for_ast_trait_ref<'a>(
&self,
span: Span,
/// **A note on binders:** there is an implied binder around
/// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
/// for more details.
- #[tracing::instrument(level = "debug", skip(self, ast_bounds, bounds))]
+ #[instrument(level = "debug", skip(self, ast_bounds, bounds))]
pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>>(
&self,
param_ty: Ty<'tcx>,
/// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
/// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
/// the binder (e.g., `&'a u32`) and hence may reference bound regions.
- #[tracing::instrument(
- level = "debug",
- skip(self, bounds, speculative, dup_bindings, path_span)
- )]
+ #[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))]
fn add_predicates_for_ast_type_binding(
&self,
hir_ref_id: hir::HirId,
let ident = Ident::new(assoc_item.name, binding.item_name.span);
let item_segment = hir::PathSegment {
ident,
- hir_id: Some(binding.hir_id),
- res: None,
+ hir_id: binding.hir_id,
+ res: Res::Err,
args: Some(binding.gen_args),
infer_args: false,
};
[.., hir::PathSegment {
ident,
args,
- res: Some(Res::Def(DefKind::Enum, _)),
+ res: Res::Def(DefKind::Enum, _),
..
}, _] => (
// We need to include the `::` in `Type::Variant::<Args>`
let types_and_spans: Vec<_> = segments
.clone()
.flat_map(|segment| {
- segment.res.and_then(|res| {
- if segment.args().args.is_empty() {
- None
- } else {
- Some((
- match res {
- Res::PrimTy(ty) => format!("{} `{}`", res.descr(), ty.name()),
+ if segment.args().args.is_empty() {
+ None
+ } else {
+ Some((
+ match segment.res {
+ Res::PrimTy(ty) => format!("{} `{}`", segment.res.descr(), ty.name()),
Res::Def(_, def_id)
if let Some(name) = self.tcx().opt_item_name(def_id) => {
- format!("{} `{name}`", res.descr())
+ format!("{} `{name}`", segment.res.descr())
}
Res::Err => "this type".to_string(),
- _ => res.descr().to_string(),
+ _ => segment.res.descr().to_string(),
},
segment.ident.span,
))
- }
- })
+ }
})
.collect();
let this_type = match &types_and_spans[..] {
/// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait
/// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors.
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
let tcx = self.tcx();
hir::TyKind::Err => tcx.ty_error(),
};
- debug!(?result_ty);
-
self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
result_ty
}
};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
- #[instrument(skip(self), level = "debug")]
+ #[instrument(skip(self), level = "debug", ret)]
pub fn check_match(
&self,
expr: &'tcx hir::Expr<'tcx>,
// We won't diverge unless the scrutinee or all arms diverge.
self.diverges.set(scrut_diverges | all_arms_diverge);
- let match_ty = coercion.complete(self);
- debug!(?match_ty);
- match_ty
+ coercion.complete(self)
}
/// When the previously checked expression (the scrutinee) diverges,
use super::method::MethodCallee;
-use super::{Expectation, FnCtxt, TupleArgumentsFlag};
+use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag};
use crate::type_error_struct;
use rustc_errors::{struct_span_err, Applicability, Diagnostic};
use rustc_span::Span;
use rustc_target::spec::abi;
use rustc_trait_selection::autoderef::Autoderef;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use std::iter;
};
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
- err.span_label(call_expr.span, "call expression requires function");
+ if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty)
+ && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
+ {
+ let descr = match maybe_def {
+ DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id),
+ DefIdOrName::Name(name) => name,
+ };
+ err.span_label(
+ callee_expr.span,
+ format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called")
+ );
+ if let DefIdOrName::DefId(def_id) = maybe_def
+ && let Some(def_span) = self.tcx.hir().span_if_local(def_id)
+ {
+ err.span_label(def_span, "the callable type is defined here");
+ }
+ } else {
+ err.span_label(call_expr.span, "call expression requires function");
+ }
}
if let Some(span) = self.tcx.hir().res_span(def) {
use hir::def_id::LOCAL_CRATE;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
-use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::cast::{CastKind, CastTy};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
/// Reifies a cast check to be checked once we have full type information for
return Err(reported);
}
- if self.type_is_known_to_be_sized_modulo_regions(t, span) {
+ if self.type_is_sized_modulo_regions(self.param_env, t, span) {
return Ok(Some(PointerKind::Thin));
}
debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
- if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span)
+ if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span)
&& !self.cast_ty.has_infer_types()
{
self.report_cast_to_unsized_type(fcx);
);
}
}
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
- fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
- let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
- traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span)
- }
-}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
match arg.kind {
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
- [
- PathSegment {
- res: Some(Res::SelfTy { trait_: _, alias_to: impl_ref }),
- ..
- },
- ] => {
+ [PathSegment { res: Res::SelfTy { trait_: _, alias_to: impl_ref }, .. }] => {
let impl_ty_name =
impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id));
self.selftys.push((path.span, impl_ty_name));
def.destructor(tcx); // force the destructor to be evaluated
if vs.is_empty() {
- if let Some(attr) = tcx.get_attr(def_id.to_def_id(), sym::repr) {
+ if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() {
struct_span_err!(
tcx.sess,
attr.span,
self.check_closure(expr, expected_kind, decl, body, gen, expected_sig)
}
- #[instrument(skip(self, expr, body, decl), level = "debug")]
+ #[instrument(skip(self, expr, body, decl), level = "debug", ret)]
fn check_closure(
&self,
expr: &hir::Expr<'_>,
},
);
- let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs);
-
- debug!(?expr.hir_id, ?closure_type);
-
- closure_type
+ self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs)
}
/// Given the expected type, figures out what it can about this closure we
/// The `cause_span` should be the span that caused us to
/// have this expected signature, or `None` if we can't readily
/// know that.
- #[instrument(level = "debug", skip(self, cause_span))]
+ #[instrument(level = "debug", skip(self, cause_span), ret)]
fn deduce_sig_from_projection(
&self,
cause_span: Option<Span>,
hir::Unsafety::Normal,
Abi::Rust,
));
- debug!(?sig);
Some(ExpectedSig { cause_span, sig })
}
/// types that the user gave into a signature.
///
/// Also, record this closure signature for later.
- #[instrument(skip(self, decl, body), level = "debug")]
+ #[instrument(skip(self, decl, body), level = "debug", ret)]
fn supplied_sig_of_closure(
&self,
hir_id: hir::HirId,
bound_vars,
);
- debug!(?result);
-
let c_result = self.inh.infcx.canonicalize_response(result);
self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
/// user specified. The "desugared" return type is an `impl
/// Future<Output = T>`, so we do this by searching through the
/// obligations to extract the `T`.
- #[instrument(skip(self), level = "debug")]
+ #[instrument(skip(self), level = "debug", ret)]
fn deduce_future_output_from_obligations(
&self,
expr_def_id: DefId,
);
self.register_predicates(obligations);
- debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty);
Some(output_ty)
}
/// For default associated types the normalization is not possible (the value
/// from the impl could be overridden). We also can't normalize generic
/// associated types (yet) because they contain bound parameters.
-#[tracing::instrument(level = "debug", skip(tcx))]
+#[instrument(level = "debug", skip(tcx))]
pub fn check_type_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ty: &ty::AssocItem,
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
self.suggest_missing_parentheses(err, expr);
self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
+ self.suggest_copied_or_cloned(err, expr, expr_ty, expected);
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
///
/// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
/// will be permitted if the diverges flag is currently "always".
- #[tracing::instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
+ #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
pub fn demand_coerce_diag(
&self,
expr: &hir::Expr<'tcx>,
let closure_params_len = closure_fn_decl.inputs.len();
let (
Some(Node::Expr(hir::Expr {
- kind: hir::ExprKind::MethodCall(method_path, method_expr, _),
+ kind: hir::ExprKind::MethodCall(method_path, receiver, ..),
..
})),
1,
return None;
};
- let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]);
+ let self_ty = self.typeck_results.borrow().expr_ty(receiver);
let name = method_path.ident.name;
let is_as_ref_able = match self_ty.peel_refs().kind() {
ty::Adt(def, _) => {
};
if self.can_coerce(ref_ty, expected) {
let mut sugg_sp = sp;
- if let hir::ExprKind::MethodCall(ref segment, ref args, _) = expr.kind {
+ if let hir::ExprKind::MethodCall(ref segment, receiver, args, _) = expr.kind {
let clone_trait =
self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span));
- if let ([arg], Some(true), sym::clone) = (
- &args[..],
- self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
+ if args.is_empty()
+ && self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
|did| {
let ai = self.tcx.associated_item(did);
ai.trait_container(self.tcx) == Some(clone_trait)
},
- ),
- segment.ident.name,
- ) {
+ ) == Some(true)
+ && segment.ident.name == sym::clone
+ {
// If this expression had a clone call when suggesting borrowing
// we want to suggest removing it because it'd now be unnecessary.
- sugg_sp = arg.span;
+ sugg_sp = receiver.span;
}
}
if let Ok(src) = sm.span_to_snippet(sugg_sp) {
}
ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),
ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected),
- ExprKind::MethodCall(segment, args, _) => {
- self.check_method_call(expr, segment, args, expected)
+ ExprKind::MethodCall(segment, receiver, args, _) => {
+ self.check_method_call(expr, segment, receiver, args, expected)
}
ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
ExprKind::Type(e, t) => {
// We just want to check sizedness, so instead of introducing
// placeholder lifetimes with probing, we just replace higher lifetimes
// with fresh vars.
- let arg_span = args.get(i).map(|a| a.span);
- let span = arg_span.unwrap_or(expr.span);
+ let span = args.get(i).map(|a| a.span).unwrap_or(expr.span);
let input = self.replace_bound_vars_with_fresh_vars(
span,
infer::LateBoundRegionConversionTime::FnCall,
fn_sig.input(i),
);
- self.require_type_is_sized(
- self.normalize_associated_types_in(span, input),
+ self.require_type_is_sized_deferred(
+ input,
span,
- traits::SizedArgumentType(arg_span),
+ traits::SizedArgumentType(None),
);
}
}
infer::LateBoundRegionConversionTime::FnCall,
fn_sig.output(),
);
- self.require_type_is_sized(
- self.normalize_associated_types_in(expr.span, output),
- expr.span,
- traits::SizedReturnType,
- );
+ self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType);
}
// We always require that the type provided as the value for
&self,
expr: &'tcx hir::Expr<'tcx>,
segment: &hir::PathSegment<'_>,
+ rcvr: &'tcx hir::Expr<'tcx>,
args: &'tcx [hir::Expr<'tcx>],
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
- let rcvr = &args[0];
let rcvr_t = self.check_expr(&rcvr);
// no need to check for bot/err -- callee does that
- let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
+ let rcvr_t = self.structurally_resolved_type(rcvr.span, rcvr_t);
let span = segment.ident.span;
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
span,
rcvr_t,
segment.ident,
- SelfSource::MethodCall(&args[0]),
+ SelfSource::MethodCall(rcvr),
error,
- Some(args),
+ Some((rcvr, args)),
) {
err.emit();
}
};
// Call the generic checker.
- self.check_method_argument_types(
- span,
- expr,
- method,
- &args[1..],
- DontTupleArguments,
- expected,
- )
+ self.check_method_argument_types(span, expr, method, &args, DontTupleArguments, expected)
}
fn check_expr_cast(
self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {})
}
- #[instrument(skip(self, mutate_fulfillment_errors), level = "debug")]
+ #[instrument(skip(self, mutate_fulfillment_errors), level = "debug", ret)]
pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment(
&self,
mut ty: Ty<'tcx>,
// indirect dependencies that don't seem worth tracking
// precisely.
self.select_obligations_where_possible(false, mutate_fulfillment_errors);
- ty = self.resolve_vars_if_possible(ty);
-
- debug!(?ty);
- ty
+ self.resolve_vars_if_possible(ty)
}
pub(in super::super) fn record_deferred_call_resolution(
}
}
+ pub fn require_type_is_sized_deferred(
+ &self,
+ ty: Ty<'tcx>,
+ span: Span,
+ code: traits::ObligationCauseCode<'tcx>,
+ ) {
+ if !ty.references_error() {
+ self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
+ }
+ }
+
pub fn register_bound(
&self,
ty: Ty<'tcx>,
if found != self.tcx.types.unit {
return;
}
- if let ExprKind::MethodCall(path_segment, [rcvr, ..], _) = expr.kind {
+ if let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind {
if self
.typeck_results
.borrow()
})
}
- #[tracing::instrument(level = "debug", skip(self, code, span, def_id, substs))]
+ #[instrument(level = "debug", skip(self, code, span, def_id, substs))]
fn add_required_obligations_with_code(
&self,
span: Span,
use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor};
use rustc_session::Session;
use rustc_span::symbol::Ident;
-use rustc_span::{self, Span};
+use rustc_span::{self, sym, Span};
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
use std::iter;
let minimum_input_count = expected_input_tys.len();
let provided_arg_count = provided_args.len();
+ let is_const_eval_select = matches!(fn_def_id, Some(def_id) if
+ self.tcx.def_kind(def_id) == hir::def::DefKind::Fn
+ && self.tcx.is_intrinsic(def_id)
+ && self.tcx.item_name(def_id) == sym::const_eval_select);
+
// We introduce a helper function to demand that a given argument satisfy a given input
// This is more complicated than just checking type equality, as arguments could be coerced
// This version writes those types back so further type checking uses the narrowed types
return Compatibility::Incompatible(coerce_error);
}
+ // Check that second and third argument of `const_eval_select` must be `FnDef`, and additionally that
+ // the second argument must be `const fn`. The first argument must be a tuple, but this is already expressed
+ // in the function signature (`F: FnOnce<ARG>`), so I did not bother to add another check here.
+ //
+ // This check is here because there is currently no way to express a trait bound for `FnDef` types only.
+ if is_const_eval_select && (1..=2).contains(&idx) {
+ if let ty::FnDef(def_id, _) = checked_ty.kind() {
+ if idx == 1 && !self.tcx.is_const_fn_raw(*def_id) {
+ self.tcx
+ .sess
+ .struct_span_err(provided_arg.span, "this argument must be a `const fn`")
+ .help("consult the documentation on `const_eval_select` for more information")
+ .emit();
+ }
+ } else {
+ self.tcx
+ .sess
+ .struct_span_err(provided_arg.span, "this argument must be a function item")
+ .note(format!("expected a function item, found {checked_ty}"))
+ .help(
+ "consult the documentation on `const_eval_select` for more information",
+ )
+ .emit();
+ }
+ }
+
// 3. Check if the formal type is a supertype of the checked one
// and register any such obligations for future type checks
let supertype_error = self
}
}
hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false),
- hir::ExprKind::MethodCall(path_segment, _, span) => {
+ hir::ExprKind::MethodCall(path_segment, _, _, span) => {
let ident_span = path_segment.ident.span;
let ident_span = if let Some(args) = path_segment.args {
ident_span.with_hi(args.span_ext.hi())
.collect();
let callee_expr = match &call_expr.peel_blocks().kind {
hir::ExprKind::Call(callee, _) => Some(*callee),
- hir::ExprKind::MethodCall(_, callee, _) => {
+ hir::ExprKind::MethodCall(_, receiver, ..) => {
if let Some((DefKind::AssocFn, def_id)) =
self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
&& let Some(assoc) = tcx.opt_associated_item(def_id)
&& assoc.fn_has_self_parameter
{
- Some(&callee[0])
+ Some(*receiver)
} else {
None
}
};
if let Some(suggestion_text) = suggestion_text {
let source_map = self.sess().source_map();
- let mut suggestion = format!(
- "{}(",
- source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| fn_def_id
- .map_or("".to_string(), |fn_def_id| tcx.item_name(fn_def_id).to_string()))
- );
+ let (mut suggestion, suggestion_span) =
+ if let Some(call_span) = full_call_span.find_ancestor_inside(error_span) {
+ ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi()))
+ } else {
+ (
+ format!(
+ "{}(",
+ source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| {
+ fn_def_id.map_or("".to_string(), |fn_def_id| {
+ tcx.item_name(fn_def_id).to_string()
+ })
+ })
+ ),
+ error_span,
+ )
+ };
let mut needs_comma = false;
for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() {
if needs_comma {
}
suggestion += ")";
err.span_suggestion_verbose(
- error_span,
+ suggestion_span,
&suggestion_text,
suggestion,
Applicability::HasPlaceholders,
param,
*call_hir_id,
callee.span,
+ None,
args,
)
{
return true;
}
}
- // Notably, we only point to params that are local to the
- // item we're checking, since those are the ones we are able
- // to look in the final `hir::PathSegment` for. Everything else
- // would require a deeper search into the `qpath` than I think
- // is worthwhile.
- if let Some(param_to_point_at) = param_to_point_at
- && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
- {
- return true;
- }
+ }
+ // Notably, we only point to params that are local to the
+ // item we're checking, since those are the ones we are able
+ // to look in the final `hir::PathSegment` for. Everything else
+ // would require a deeper search into the `qpath` than I think
+ // is worthwhile.
+ if let Some(param_to_point_at) = param_to_point_at
+ && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
+ {
+ return true;
}
}
- hir::ExprKind::MethodCall(segment, args, ..) => {
+ hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter()
.flatten()
param,
hir_id,
segment.ident.span,
+ Some(receiver),
args,
) {
return true;
param_to_point_at: ty::GenericArg<'tcx>,
call_hir_id: hir::HirId,
callee_span: Span,
- args: &[hir::Expr<'tcx>],
+ receiver: Option<&'tcx hir::Expr<'tcx>>,
+ args: &'tcx [hir::Expr<'tcx>],
) -> bool {
let sig = self.tcx.fn_sig(def_id).skip_binder();
let args_referencing_param: Vec<_> = sig
.enumerate()
.filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at))
.collect();
-
// If there's one field that references the given generic, great!
- if let [(idx, _)] = args_referencing_param.as_slice() && let Some(arg) = args.get(*idx) {
+ if let [(idx, _)] = args_referencing_param.as_slice()
+ && let Some(arg) = receiver
+ .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
error.obligation.cause.map_code(|parent_code| {
ObligationCauseCode::FunctionArgumentObligation {
use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
use rustc_span::symbol::sym;
use rustc_span::Span;
+use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
- fn extract_callable_info(
+ /// Extracts information about a callable type for diagnostics. This is a
+ /// heuristic -- it doesn't necessarily mean that a type is always callable,
+ /// because the callable type must also be well-formed to be called.
+ pub(in super::super) fn extract_callable_info(
&self,
expr: &Expr<'_>,
found: Ty<'tcx>,
}
}
+ pub(crate) fn suggest_copied_or_cloned(
+ &self,
+ diag: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ expr_ty: Ty<'tcx>,
+ expected_ty: Ty<'tcx>,
+ ) {
+ let ty::Adt(adt_def, substs) = expr_ty.kind() else { return; };
+ let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return; };
+ if adt_def != expected_adt_def {
+ return;
+ }
+
+ let mut suggest_copied_or_cloned = || {
+ let expr_inner_ty = substs.type_at(0);
+ let expected_inner_ty = expected_substs.type_at(0);
+ if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
+ && self.can_eq(self.param_env, *ty, expected_inner_ty).is_ok()
+ {
+ let def_path = self.tcx.def_path_str(adt_def.did());
+ if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) {
+ diag.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ format!(
+ "use `{def_path}::copied` to copy the value inside the `{def_path}`"
+ ),
+ ".copied()",
+ Applicability::MachineApplicable,
+ );
+ } else if let Some(clone_did) = self.tcx.lang_items().clone_trait()
+ && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
+ self,
+ self.param_env,
+ *ty,
+ clone_did,
+ expr.span
+ )
+ {
+ diag.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ format!(
+ "use `{def_path}::cloned` to clone the value inside the `{def_path}`"
+ ),
+ ".cloned()",
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ };
+
+ if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result)
+ && adt_def.did() == result_did
+ // Check that the error types are equal
+ && self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1)).is_ok()
+ {
+ suggest_copied_or_cloned();
+ } else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option)
+ && adt_def.did() == option_did
+ {
+ suggest_copied_or_cloned();
+ }
+ }
+
/// Suggest wrapping the block in square brackets instead of curly braces
/// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
pub(crate) fn suggest_block_to_brackets(
found_ty: Ty<'tcx>,
expr: &hir::Expr<'_>,
) {
- let hir::ExprKind::MethodCall(segment, &[ref callee_expr], _) = expr.kind else { return; };
+ let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else { return; };
let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; };
let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return };
let results = self.typeck_results.borrow();
}
}
-enum DefIdOrName {
+pub enum DefIdOrName {
DefId(DefId),
Name(&'static str),
}
use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable};
use rustc_span::symbol::sym;
use rustc_span::Span;
-use tracing::debug;
mod drop_ranges;
}) {
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
} else {
- debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id));
- match self.fcx.tcx.hir().find_parent_node(expr.hir_id) {
+ let parent_expr = self
+ .fcx
+ .tcx
+ .hir()
+ .parent_iter(expr.hir_id)
+ .find(|(_, node)| matches!(node, hir::Node::Expr(_)))
+ .map(|(id, _)| id);
+ debug!("parent_expr: {:?}", parent_expr);
+ match parent_expr {
Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }),
None => {
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
self.handle_uninhabited_return(expr);
}
- ExprKind::MethodCall(_, exprs, _) => {
+ ExprKind::MethodCall(_, receiver, exprs, _) => {
+ self.visit_expr(receiver);
for expr in exprs {
self.visit_expr(expr);
}
bk: rustc_middle::ty::BorrowKind,
) {
debug!(
- "borrow: place_with_id = {place_with_id:?}, diag_expr_id={diag_expr_id:?}, \
- borrow_kind={bk:?}"
+ "borrow: place_with_id = {place_with_id:#?}, diag_expr_id={diag_expr_id:#?}, \
+ borrow_kind={bk:#?}"
);
self.borrow_place(place_with_id);
pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
+ // Some additional `Sized` obligations badly affect type inference.
+ // These obligations are added in a later stage of typeck.
+ // Removing these may also cause additional complications, see #101066.
+ pub(super) deferred_sized_obligations:
+ RefCell<Vec<(Ty<'tcx>, Span, traits::ObligationCauseCode<'tcx>)>>,
+
// When we process a call like `c()` where `c` is a closure type,
// we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
// `FnOnce` closure. In that case, we defer full resolution of the
infcx,
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)),
locals: RefCell::new(Default::default()),
+ deferred_sized_obligations: RefCell::new(Vec::new()),
deferred_call_resolutions: RefCell::new(Default::default()),
deferred_cast_checks: RefCell::new(Vec::new()),
deferred_transmute_checks: RefCell::new(Vec::new()),
/// * `call_expr`: the complete method call: (`foo.bar::<T1,...Tn>(...)`)
/// * `self_expr`: the self expression (`foo`)
/// * `args`: the expressions of the arguments (`a, b + 1, ...`)
- #[instrument(level = "debug", skip(self, call_expr, self_expr))]
+ #[instrument(level = "debug", skip(self))]
pub fn lookup_method(
&self,
self_ty: Ty<'tcx>,
self_expr: &'tcx hir::Expr<'tcx>,
args: &'tcx [hir::Expr<'tcx>],
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
- debug!(
- "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
- segment.ident, self_ty, call_expr, self_expr
- );
-
let pick =
self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
/// In particular, it doesn't really do any probing: it simply constructs
/// an obligation for a particular trait with the given self type and checks
/// whether that trait is implemented.
- #[instrument(level = "debug", skip(self, span, opt_input_types))]
+ #[instrument(level = "debug", skip(self, span))]
pub(super) fn lookup_method_in_trait(
&self,
span: Span,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
- debug!(
- "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})",
- self_ty, m_name, trait_def_id, opt_input_types
- );
-
let (obligation, substs) =
self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
self.construct_obligation_for_trait(
/// * `self_ty`: the type to search within (`Foo`)
/// * `self_ty_span` the span for the type being searched within (span of `Foo`)
/// * `expr_id`: the [`hir::HirId`] of the expression composing the entire call
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
pub fn resolve_fully_qualified_call(
&self,
span: Span,
self_ty_span: Span,
expr_id: hir::HirId,
) -> Result<(DefKind, DefId), MethodError<'tcx>> {
- debug!(
- "resolve_fully_qualified_call: method_name={:?} self_ty={:?} expr_id={:?}",
- method_name, self_ty, expr_id,
- );
-
let tcx = self.tcx;
// Check if we have an enum variant.
&pick,
);
- debug!("resolve_fully_qualified_call: pick={:?}", pick);
+ debug!(?pick);
{
let mut typeck_results = self.typeck_results.borrow_mut();
let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap();
for import_id in pick.import_ids {
- debug!("resolve_fully_qualified_call: used_trait_import: {:?}", import_id);
+ debug!(used_trait_import=?import_id);
used_trait_imports.insert(import_id);
}
}
let def_kind = pick.item.kind.as_def_kind();
- debug!(
- "resolve_fully_qualified_call: def_kind={:?}, def_id={:?}",
- def_kind, pick.item.def_id
- );
tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span));
Ok((def_kind, pick.item.def_id))
}
if precise {
let args = args
.iter()
- .skip(1)
.map(|arg| {
let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
format!(
/// would result in an error (basically, the same criteria we
/// would use to decide if a method is a plausible fit for
/// ambiguity purposes).
- #[instrument(level = "debug", skip(self, scope_expr_id))]
+ #[instrument(level = "debug", skip(self))]
pub fn probe_for_return_type(
&self,
span: Span,
self_ty: Ty<'tcx>,
scope_expr_id: hir::HirId,
) -> Vec<ty::AssocItem> {
- debug!(
- "probe(self_ty={:?}, return_type={}, scope_expr_id={})",
- self_ty, return_type, scope_expr_id
- );
let method_names = self
.probe_op(
span,
.collect()
}
- #[instrument(level = "debug", skip(self, scope_expr_id))]
+ #[instrument(level = "debug", skip(self))]
pub fn probe_for_name(
&self,
span: Span,
scope_expr_id: hir::HirId,
scope: ProbeScope,
) -> PickResult<'tcx> {
- debug!(
- "probe(self_ty={:?}, item_name={}, scope_expr_id={})",
- self_ty, item_name, scope_expr_id
- );
self.probe_op(
span,
mode,
use rustc_middle::traits::util::supertraits;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::print::with_crate_prefix;
-use rustc_middle::ty::ToPolyTraitRef;
use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
use std::cmp::Ordering;
use std::iter;
-use super::probe::{Mode, ProbeScope};
+use super::probe::{IsSuggestion, Mode, ProbeScope};
use super::{CandidateSource, MethodError, NoMatchData};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name: Ident,
source: SelfSource<'tcx>,
error: MethodError<'tcx>,
- args: Option<&'tcx [hir::Expr<'tcx>]>,
+ args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
// Avoid suggestions when we don't know what's going on.
if rcvr_ty.references_error() {
span,
rcvr_ty,
item_name,
- args.map(|args| args.len()),
+ args.map(|(_, args)| args.len() + 1),
source,
out_of_scope_traits,
&unsatisfied_predicates,
}
}
+ self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
+
return Some(err);
}
}
}
+ fn check_for_deref_method(
+ &self,
+ err: &mut Diagnostic,
+ self_source: SelfSource<'tcx>,
+ rcvr_ty: Ty<'tcx>,
+ item_name: Ident,
+ ) {
+ let SelfSource::QPath(ty) = self_source else { return; };
+ for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) {
+ if let Ok(pick) = self.probe_for_name(
+ ty.span,
+ Mode::Path,
+ item_name,
+ IsSuggestion(true),
+ deref_ty,
+ ty.hir_id,
+ ProbeScope::TraitsInScope,
+ ) {
+ if deref_ty.is_suggestable(self.tcx, true)
+ // If this method receives `&self`, then the provided
+ // argument _should_ coerce, so it's valid to suggest
+ // just changing the path.
+ && pick.item.fn_has_self_parameter
+ && let Some(self_ty) =
+ self.tcx.fn_sig(pick.item.def_id).inputs().skip_binder().get(0)
+ && self_ty.is_ref()
+ {
+ let suggested_path = match deref_ty.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Adt(_, _)
+ | ty::Str
+ | ty::Projection(_)
+ | ty::Param(_) => format!("{deref_ty}"),
+ _ => format!("<{deref_ty}>"),
+ };
+ err.span_suggestion_verbose(
+ ty.span,
+ format!("the function `{item_name}` is implemented on `{deref_ty}`"),
+ suggested_path,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_note(
+ ty.span,
+ format!("the function `{item_name}` is implemented on `{deref_ty}`"),
+ );
+ }
+ return;
+ }
+ }
+ }
+
/// Print out the type for use in value namespace.
fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
match ty.kind() {
fn print_disambiguation_help<'tcx>(
item_name: Ident,
- args: Option<&'tcx [hir::Expr<'tcx>]>,
+ args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
err: &mut Diagnostic,
trait_name: String,
rcvr_ty: Ty<'_>,
fn_has_self_parameter: bool,
) {
let mut applicability = Applicability::MachineApplicable;
- let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
+ let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
let args = format!(
"({}{})",
if rcvr_ty.is_region_ptr() {
} else {
""
},
- args.iter()
+ std::iter::once(receiver)
+ .chain(args.iter())
.map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
applicability = Applicability::HasPlaceholders;
"_".to_owned()
typeck_with_fallback(tcx, def_id, fallback)
}
-#[instrument(skip(tcx, fallback))]
fn typeck_with_fallback<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
fcx.resolve_rvalue_scopes(def_id.to_def_id());
fcx.resolve_generator_interiors(def_id.to_def_id());
+ for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
+ let ty = fcx.normalize_ty(span, ty);
+ fcx.require_type_is_sized(ty, span, code);
+ }
+
fcx.select_all_obligations_or_error();
if !fcx.infcx.is_tainted_by_errors() {
)
.is_ok()
{
- // Suppress this error, since we already emitted
- // a deref suggestion in check_overloaded_binop
- err.downgrade_to_delayed_bug();
+ // If LHS += RHS is an error, but *LHS += RHS is successful, then we will have
+ // emitted a better suggestion during error handling in check_overloaded_binop.
+ if self
+ .lookup_op_method(
+ lhs_ty,
+ Some(rhs_ty),
+ Some(rhs),
+ Op::Binary(op, IsAssign::Yes),
+ expected,
+ )
+ .is_err()
+ {
+ err.downgrade_to_delayed_bug();
+ } else {
+ // Otherwise, it's valid to suggest dereferencing the LHS here.
+ err.span_suggestion_verbose(
+ lhs.span.shrink_to_lo(),
+ "consider dereferencing the left-hand side of this operation",
+ "*",
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
});
) -> Ty<'tcx> {
// Determine the binding mode...
let bm = match ba {
- hir::BindingAnnotation::Unannotated => def_bm,
+ hir::BindingAnnotation::NONE => def_bm,
_ => BindingMode::convert(ba),
};
// ...and store it in a side table:
ba: hir::BindingAnnotation,
) {
match (expected.kind(), actual.kind(), ba) {
- (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::Unannotated)
+ (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::NONE)
if self.can_eq(self.param_env, *inner_ty, actual).is_ok() =>
{
err.span_suggestion_verbose(
Applicability::MaybeIncorrect,
);
}
- (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::Ref)
+ (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::REF)
if self.can_eq(self.param_env, expected, *inner_ty).is_ok() =>
{
err.span_suggestion_verbose(
// & expression, and its lifetime would be extended to the end of the block (due
// to a different rule, not the below code).
match pat.kind {
- PatKind::Binding(hir::BindingAnnotation::Ref, ..)
- | PatKind::Binding(hir::BindingAnnotation::RefMut, ..) => true,
+ PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true,
PatKind::Struct(_, ref field_pats, _) => {
field_pats.iter().any(|fp| is_binding_pat(&fp.pat))
PatKind::Box(ref subpat) => is_binding_pat(&subpat),
PatKind::Ref(_, _)
- | PatKind::Binding(
- hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
- ..,
- )
+ | PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
| PatKind::Wild
| PatKind::Path(_)
| PatKind::Lit(_)
tcx: TyCtxt<'_>,
closure_id: hir::HirId,
) -> bool {
+ if tcx.sess.rust_2021() {
+ return false;
+ }
+
let (level, _) =
tcx.lint_level_at_node(lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, closure_id);
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
match ty.kind {
hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments {
- [s] => s.res.and_then(|r| r.opt_def_id()) == Some(trait_def_id.to_def_id()),
+ [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()),
_ => false,
},
_ => false,
}
}
-#[tracing::instrument(level = "debug", skip(tcx, span, sig_if_method))]
+#[instrument(level = "debug", skip(tcx, span, sig_if_method))]
fn check_associated_item(
tcx: TyCtxt<'_>,
item_id: LocalDefId,
});
}
-#[tracing::instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))]
+#[instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))]
fn check_impl<'tcx>(
tcx: TyCtxt<'tcx>,
item: &'tcx hir::Item<'tcx>,
wfcx.register_obligations(obligations);
}
-#[tracing::instrument(level = "debug", skip(wfcx, span, hir_decl))]
+#[instrument(level = "debug", skip(wfcx, span, hir_decl))]
fn check_fn_or_method<'tcx>(
wfcx: &WfCheckingCtxt<'_, 'tcx>,
span: Span,
`self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \
of the previous types except `Self`)";
-#[tracing::instrument(level = "debug", skip(wfcx))]
+#[instrument(level = "debug", skip(wfcx))]
fn check_method_receiver<'tcx>(
wfcx: &WfCheckingCtxt<'_, 'tcx>,
fn_sig: &hir::FnSig<'_>,
use rustc_errors::{Applicability, StashKey};
use rustc_hir as hir;
-use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit;
use rustc_hir::intravisit::Visitor;
/// Computes the relevant generic parameter for a potential generic const argument.
///
/// This should be called using the query `tcx.opt_const_param_of`.
-#[instrument(level = "debug", skip(tcx))]
pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
use hir::*;
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
args.args
.iter()
.filter(|arg| arg.is_ty_or_const())
- .position(|arg| arg.id() == hir_id)
+ .position(|arg| arg.hir_id() == hir_id)
})
.unwrap_or_else(|| {
bug!("no arg matching AnonConst in segment");
args.args
.iter()
.filter(|arg| arg.is_ty_or_const())
- .position(|arg| arg.id() == hir_id)
+ .position(|arg| arg.hir_id() == hir_id)
})
.unwrap_or_else(|| {
bug!("no arg matching AnonConst in segment");
args.args
.iter()
.filter(|arg| arg.is_ty_or_const())
- .position(|arg| arg.id() == hir_id)
+ .position(|arg| arg.hir_id() == hir_id)
.map(|index| (index, seg)).or_else(|| args.bindings
.iter()
.filter_map(TypeBinding::opt_const)
return None;
};
- // Try to use the segment resolution if it is valid, otherwise we
- // default to the path resolution.
- let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
- let generics = match tcx.res_generics_def_id(res) {
+ let generics = match tcx.res_generics_def_id(segment.res) {
Some(def_id) => tcx.generics_of(def_id),
None => {
tcx.sess.delay_span_bug(
tcx.def_span(def_id),
- &format!("unexpected anon const res {:?} in path: {:?}", res, path),
+ &format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
);
return None;
}
.iter()
.filter_map(|seg| seg.args)
.flat_map(|args| args.args)
- .any(|arg| arg.id() == arg_id)
+ .any(|arg| arg.hir_id() == arg_id)
};
let mut arg_path = None;
pat.walk(|pat| match pat.kind {
self.consume_exprs(args);
}
- hir::ExprKind::MethodCall(.., args, _) => {
+ hir::ExprKind::MethodCall(.., receiver, args, _) => {
// callee.m(args)
+ self.consume_expr(receiver);
self.consume_exprs(args);
}
fn check_for_entry_fn(tcx: TyCtxt<'_>) {
match tcx.entry_fn(()) {
- Some((def_id, EntryFnType::Main)) => check_main_fn_ty(tcx, def_id),
+ Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
_ => {}
}
// Creates lifetime name suggestions from the lifetime parameter names
fn get_lifetime_args_suggestions_from_param_names(
&self,
- path_hir_id: Option<hir::HirId>,
+ path_hir_id: hir::HirId,
num_params_to_take: usize,
) -> String {
debug!(?path_hir_id);
- if let Some(path_hir_id) = path_hir_id {
- let mut ret = Vec::new();
- for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
- debug!(?id);
- let params = if let Some(generics) = node.generics() {
- generics.params
- } else if let hir::Node::Ty(ty) = node
- && let hir::TyKind::BareFn(bare_fn) = ty.kind
- {
- bare_fn.generic_params
- } else {
- &[]
- };
- ret.extend(params.iter().filter_map(|p| {
- let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
- = p.kind
- else { return None };
- let hir::ParamName::Plain(name) = p.name else { return None };
- Some(name.to_string())
- }));
- // Suggest `'static` when in const/static item-like.
- if let hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
- ..
- })
- | hir::Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Const { .. },
- ..
- })
- | hir::Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Const { .. },
- ..
- })
- | hir::Node::ForeignItem(hir::ForeignItem {
- kind: hir::ForeignItemKind::Static { .. },
- ..
- })
- | hir::Node::AnonConst(..) = node
- {
- ret.extend(
- std::iter::repeat("'static".to_owned())
- .take(num_params_to_take.saturating_sub(ret.len())),
- );
- }
- if ret.len() >= num_params_to_take {
- return ret[..num_params_to_take].join(", ");
- }
- // We cannot refer to lifetimes defined in an outer function.
- if let hir::Node::Item(_) = node {
- break;
- }
+ let mut ret = Vec::new();
+ for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
+ debug!(?id);
+ let params = if let Some(generics) = node.generics() {
+ generics.params
+ } else if let hir::Node::Ty(ty) = node
+ && let hir::TyKind::BareFn(bare_fn) = ty.kind
+ {
+ bare_fn.generic_params
+ } else {
+ &[]
+ };
+ ret.extend(params.iter().filter_map(|p| {
+ let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
+ = p.kind
+ else { return None };
+ let hir::ParamName::Plain(name) = p.name else { return None };
+ Some(name.to_string())
+ }));
+ // Suggest `'static` when in const/static item-like.
+ if let hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
+ ..
+ })
+ | hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Const { .. },
+ ..
+ })
+ | hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Const { .. },
+ ..
+ })
+ | hir::Node::ForeignItem(hir::ForeignItem {
+ kind: hir::ForeignItemKind::Static { .. },
+ ..
+ })
+ | hir::Node::AnonConst(..) = node
+ {
+ ret.extend(
+ std::iter::repeat("'static".to_owned())
+ .take(num_params_to_take.saturating_sub(ret.len())),
+ );
+ }
+ if ret.len() >= num_params_to_take {
+ return ret[..num_params_to_take].join(", ");
+ }
+ // We cannot refer to lifetimes defined in an outer function.
+ if let hir::Node::Item(_) = node {
+ break;
}
}
num = num_trait_generics_except_self,
);
- if let Some(hir_id) = self.path_segment.hir_id
- && let Some(parent_node) = self.tcx.hir().find_parent_node(hir_id)
+ if let Some(parent_node) = self.tcx.hir().find_parent_node(self.path_segment.hir_id)
&& let Some(parent_node) = self.tcx.hir().find(parent_node)
&& let hir::Node::Expr(expr) = parent_node {
match expr.kind {
num_assoc_fn_excess_args: usize,
num_trait_generics_except_self: usize,
) {
- if let hir::ExprKind::MethodCall(_, args, _) = expr.kind {
- assert_eq!(args.len(), 1);
+ if let hir::ExprKind::MethodCall(_, receiver, args, ..) = expr.kind {
+ assert_eq!(args.len(), 0);
if num_assoc_fn_excess_args == num_trait_generics_except_self {
if let Some(gen_args) = self.gen_args.span_ext()
&& let Ok(gen_args) = self.tcx.sess.source_map().span_to_snippet(gen_args)
- && let Ok(args) = self.tcx.sess.source_map().span_to_snippet(args[0].span) {
- let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), args);
+ && let Ok(receiver) = self.tcx.sess.source_map().span_to_snippet(receiver.span) {
+ let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), receiver);
err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect);
}
}
# target.
#llvm-config = <none> (path)
+# Override detection of whether this is a Rust-patched LLVM. This would be used
+# in conjunction with either an llvm-config or build.submodules = false.
+#llvm-has-rust-patches = if llvm-config { false } else { true }
+
# Normally the build system can find LLVM's FileCheck utility, but if
# not, you can specify an explicit file name for it.
#llvm-filecheck = "/path/to/llvm-version/bin/FileCheck"
/// A iterator for deduping the key of a sorted iterator.
/// When encountering the duplicated key, only the last key-value pair is yielded.
///
-/// Used by [`BTreeMap::bulk_build_from_sorted_iter`].
+/// Used by [`BTreeMap::bulk_build_from_sorted_iter`][1].
+///
+/// [1]: crate::collections::BTreeMap::bulk_build_from_sorted_iter
pub struct DedupSortedIter<K, V, I>
where
I: Iterator<Item = (K, V)>,
#![feature(ptr_metadata)]
#![feature(ptr_sub_ptr)]
#![feature(receiver_trait)]
+#![feature(saturating_int_impl)]
#![feature(set_ptr_value)]
#![feature(slice_from_ptr_range)]
#![feature(slice_group_by)]
+use core::num::{Saturating, Wrapping};
+
use crate::boxed::Box;
#[rustc_specialization_trait]
NonZeroUsize,
NonZeroIsize,
);
+
+unsafe impl<T: IsZero> IsZero for Wrapping<T> {
+ #[inline]
+ fn is_zero(&self) -> bool {
+ self.0.is_zero()
+ }
+}
+
+unsafe impl<T: IsZero> IsZero for Saturating<T> {
+ #[inline]
+ fn is_zero(&self) -> bool {
+ self.0.is_zero()
+ }
+}
-Subproject commit 4e5a3f72929f152752d5659e95bb15c8f6b41eff
+Subproject commit 07872f28cd8a65c3c7428811548dc85f1f2fb05b
/// impl Provider for SomeConcreteType {
/// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
/// demand.provide_ref::<str>(&self.field)
- /// .provide_value::<i32>(|| self.num_field);
+ /// .provide_value::<i32>(self.num_field);
/// }
/// }
/// ```
///
/// # Examples
///
+ /// Provides an `u8`.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ /// # struct SomeConcreteType { field: u8 }
+ ///
+ /// impl Provider for SomeConcreteType {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// demand.provide_value::<u8>(self.field);
+ /// }
+ /// }
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn provide_value<T>(&mut self, value: T) -> &mut Self
+ where
+ T: 'static,
+ {
+ self.provide::<tags::Value<T>>(value)
+ }
+
+ /// Provide a value or other type with only static lifetimes computed using a closure.
+ ///
+ /// # Examples
+ ///
/// Provides a `String` by cloning.
///
/// ```rust
- /// # #![feature(provide_any)]
+ /// #![feature(provide_any)]
+ ///
/// use std::any::{Provider, Demand};
/// # struct SomeConcreteType { field: String }
///
/// impl Provider for SomeConcreteType {
/// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
- /// demand.provide_value::<String>(|| self.field.clone());
+ /// demand.provide_value_with::<String>(|| self.field.clone());
/// }
/// }
/// ```
#[unstable(feature = "provide_any", issue = "96024")]
- pub fn provide_value<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self
+ pub fn provide_value_with<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self
where
T: 'static,
{
self.provide_with::<tags::Value<T>>(fulfil)
}
- /// Provide a reference, note that the referee type must be bounded by `'static`,
+ /// Provide a reference. The referee type must be bounded by `'static`,
/// but may be unsized.
///
/// # Examples
/// Provides a reference to a field as a `&str`.
///
/// ```rust
- /// # #![feature(provide_any)]
+ /// #![feature(provide_any)]
+ ///
/// use std::any::{Provider, Demand};
/// # struct SomeConcreteType { field: String }
///
self.provide::<tags::Ref<tags::MaybeSizedValue<T>>>(value)
}
+ /// Provide a reference computed using a closure. The referee type
+ /// must be bounded by `'static`, but may be unsized.
+ ///
+ /// # Examples
+ ///
+ /// Provides a reference to a field as a `&str`.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ /// # struct SomeConcreteType { business: String, party: String }
+ /// # fn today_is_a_weekday() -> bool { true }
+ ///
+ /// impl Provider for SomeConcreteType {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// demand.provide_ref_with::<str>(|| {
+ /// if today_is_a_weekday() {
+ /// &self.business
+ /// } else {
+ /// &self.party
+ /// }
+ /// });
+ /// }
+ /// }
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn provide_ref_with<T: ?Sized + 'static>(
+ &mut self,
+ fulfil: impl FnOnce() -> &'a T,
+ ) -> &mut Self {
+ self.provide_with::<tags::Ref<tags::MaybeSizedValue<T>>>(fulfil)
+ }
+
/// Provide a value with the given `Type` tag.
fn provide<I>(&mut self, value: I::Reified) -> &mut Self
where
}
self
}
+
+ /// Check if the `Demand` would be satisfied if provided with a
+ /// value of the specified type. If the type does not match or has
+ /// already been provided, returns false.
+ ///
+ /// # Examples
+ ///
+ /// Check if an `u8` still needs to be provided and then provides
+ /// it.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ ///
+ /// struct Parent(Option<u8>);
+ ///
+ /// impl Provider for Parent {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// if let Some(v) = self.0 {
+ /// demand.provide_value::<u8>(v);
+ /// }
+ /// }
+ /// }
+ ///
+ /// struct Child {
+ /// parent: Parent,
+ /// }
+ ///
+ /// impl Child {
+ /// // Pretend that this takes a lot of resources to evaluate.
+ /// fn an_expensive_computation(&self) -> Option<u8> {
+ /// Some(99)
+ /// }
+ /// }
+ ///
+ /// impl Provider for Child {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// // In general, we don't know if this call will provide
+ /// // an `u8` value or not...
+ /// self.parent.provide(demand);
+ ///
+ /// // ...so we check to see if the `u8` is needed before
+ /// // we run our expensive computation.
+ /// if demand.would_be_satisfied_by_value_of::<u8>() {
+ /// if let Some(v) = self.an_expensive_computation() {
+ /// demand.provide_value::<u8>(v);
+ /// }
+ /// }
+ ///
+ /// // The demand will be satisfied now, regardless of if
+ /// // the parent provided the value or we did.
+ /// assert!(!demand.would_be_satisfied_by_value_of::<u8>());
+ /// }
+ /// }
+ ///
+ /// let parent = Parent(Some(42));
+ /// let child = Child { parent };
+ /// assert_eq!(Some(42), std::any::request_value::<u8>(&child));
+ ///
+ /// let parent = Parent(None);
+ /// let child = Child { parent };
+ /// assert_eq!(Some(99), std::any::request_value::<u8>(&child));
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn would_be_satisfied_by_value_of<T>(&self) -> bool
+ where
+ T: 'static,
+ {
+ self.would_be_satisfied_by::<tags::Value<T>>()
+ }
+
+ /// Check if the `Demand` would be satisfied if provided with a
+ /// reference to a value of the specified type. If the type does
+ /// not match or has already been provided, returns false.
+ ///
+ /// # Examples
+ ///
+ /// Check if a `&str` still needs to be provided and then provides
+ /// it.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ ///
+ /// struct Parent(Option<String>);
+ ///
+ /// impl Provider for Parent {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// if let Some(v) = &self.0 {
+ /// demand.provide_ref::<str>(v);
+ /// }
+ /// }
+ /// }
+ ///
+ /// struct Child {
+ /// parent: Parent,
+ /// name: String,
+ /// }
+ ///
+ /// impl Child {
+ /// // Pretend that this takes a lot of resources to evaluate.
+ /// fn an_expensive_computation(&self) -> Option<&str> {
+ /// Some(&self.name)
+ /// }
+ /// }
+ ///
+ /// impl Provider for Child {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// // In general, we don't know if this call will provide
+ /// // a `str` reference or not...
+ /// self.parent.provide(demand);
+ ///
+ /// // ...so we check to see if the `&str` is needed before
+ /// // we run our expensive computation.
+ /// if demand.would_be_satisfied_by_ref_of::<str>() {
+ /// if let Some(v) = self.an_expensive_computation() {
+ /// demand.provide_ref::<str>(v);
+ /// }
+ /// }
+ ///
+ /// // The demand will be satisfied now, regardless of if
+ /// // the parent provided the reference or we did.
+ /// assert!(!demand.would_be_satisfied_by_ref_of::<str>());
+ /// }
+ /// }
+ ///
+ /// let parent = Parent(Some("parent".into()));
+ /// let child = Child { parent, name: "child".into() };
+ /// assert_eq!(Some("parent"), std::any::request_ref::<str>(&child));
+ ///
+ /// let parent = Parent(None);
+ /// let child = Child { parent, name: "child".into() };
+ /// assert_eq!(Some("child"), std::any::request_ref::<str>(&child));
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn would_be_satisfied_by_ref_of<T>(&self) -> bool
+ where
+ T: ?Sized + 'static,
+ {
+ self.would_be_satisfied_by::<tags::Ref<tags::MaybeSizedValue<T>>>()
+ }
+
+ fn would_be_satisfied_by<I>(&self) -> bool
+ where
+ I: tags::Type<'a>,
+ {
+ matches!(self.0.downcast::<I>(), Some(TaggedOption(None)))
+ }
}
#[unstable(feature = "provide_any", issue = "96024")]
/// Returns some reference to the dynamic value if it is tagged with `I`,
/// or `None` otherwise.
#[inline]
+ fn downcast<I>(&self) -> Option<&TaggedOption<'a, I>>
+ where
+ I: tags::Type<'a>,
+ {
+ if self.tag_id() == TypeId::of::<I>() {
+ // SAFETY: Just checked whether we're pointing to an I.
+ Some(unsafe { &*(self as *const Self).cast::<TaggedOption<'a, I>>() })
+ } else {
+ None
+ }
+ }
+
+ /// Returns some mutable reference to the dynamic value if it is tagged with `I`,
+ /// or `None` otherwise.
+ #[inline]
fn downcast_mut<I>(&mut self) -> Option<&mut TaggedOption<'a, I>>
where
I: tags::Type<'a>,
/// assert!(!'中'.is_lowercase());
/// assert!(!' '.is_lowercase());
/// ```
+ ///
+ /// In a const context:
+ ///
+ /// ```
+ /// #![feature(const_unicode_case_lookup)]
+ /// const CAPITAL_DELTA_IS_LOWERCASE: bool = 'Δ'.is_lowercase();
+ /// assert!(!CAPITAL_DELTA_IS_LOWERCASE);
+ /// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
#[inline]
- pub fn is_lowercase(self) -> bool {
+ pub const fn is_lowercase(self) -> bool {
match self {
'a'..='z' => true,
c => c > '\x7f' && unicode::Lowercase(c),
/// assert!(!'中'.is_uppercase());
/// assert!(!' '.is_uppercase());
/// ```
+ ///
+ /// In a const context:
+ ///
+ /// ```
+ /// #![feature(const_unicode_case_lookup)]
+ /// const CAPITAL_DELTA_IS_UPPERCASE: bool = 'Δ'.is_uppercase();
+ /// assert!(CAPITAL_DELTA_IS_UPPERCASE);
+ /// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
#[inline]
- pub fn is_uppercase(self) -> bool {
+ pub const fn is_uppercase(self) -> bool {
match self {
'A'..='Z' => true,
c => c > '\x7f' && unicode::Uppercase(c),
)]
#![allow(missing_docs)]
-use crate::marker::{Destruct, DiscriminantKind};
+#[cfg(bootstrap)]
+use crate::marker::Destruct;
+use crate::marker::DiscriminantKind;
use crate::mem;
// These imports are used for simplifying intra-doc links
/// `ptr` must point to a vtable.
/// The intrinsic will return the alignment stored in that vtable.
pub fn vtable_align(ptr: *const ()) -> usize;
+
+ /// Selects which function to call depending on the context.
+ ///
+ /// If this function is evaluated at compile-time, then a call to this
+ /// intrinsic will be replaced with a call to `called_in_const`. It gets
+ /// replaced with a call to `called_at_rt` otherwise.
+ ///
+ /// # Type Requirements
+ ///
+ /// The two functions must be both function items. They cannot be function
+ /// pointers or closures. The first function must be a `const fn`.
+ ///
+ /// `arg` will be the tupled arguments that will be passed to either one of
+ /// the two functions, therefore, both functions must accept the same type of
+ /// arguments. Both functions must return RET.
+ ///
+ /// # Safety
+ ///
+ /// The two functions must behave observably equivalent. Safe code in other
+ /// crates may assume that calling a `const fn` at compile-time and at run-time
+ /// produces the same result. A function that produces a different result when
+ /// evaluated at run-time, or has any other observable side-effects, is
+ /// *unsound*.
+ ///
+ /// Here is an example of how this could cause a problem:
+ /// ```no_run
+ /// #![feature(const_eval_select)]
+ /// #![feature(core_intrinsics)]
+ /// use std::hint::unreachable_unchecked;
+ /// use std::intrinsics::const_eval_select;
+ ///
+ /// // Crate A
+ /// pub const fn inconsistent() -> i32 {
+ /// fn runtime() -> i32 { 1 }
+ /// const fn compiletime() -> i32 { 2 }
+ ///
+ /// unsafe {
+ // // ⚠ This code violates the required equivalence of `compiletime`
+ /// // and `runtime`.
+ /// const_eval_select((), compiletime, runtime)
+ /// }
+ /// }
+ ///
+ /// // Crate B
+ /// const X: i32 = inconsistent();
+ /// let x = inconsistent();
+ /// if x != X { unsafe { unreachable_unchecked(); }}
+ /// ```
+ ///
+ /// This code causes Undefined Behavior when being run, since the
+ /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
+ /// which violates the principle that a `const fn` must behave the same at
+ /// compile-time and at run-time. The unsafe code in crate B is fine.
+ #[cfg(not(bootstrap))]
+ #[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
+ pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
+ where
+ G: FnOnce<ARG, Output = RET>,
+ F: FnOnce<ARG, Output = RET>;
}
// Some functions are defined here because they accidentally got made
/// Check that the preconditions of an unsafe function are followed, if debug_assertions are on,
/// and only at runtime.
///
+/// This macro should be called as `assert_unsafe_precondition!([Generics](name: Type) => Expression)`
+/// where the names specified will be moved into the macro as captured variables, and defines an item
+/// to call `const_eval_select` on. The tokens inside the square brackets are used to denote generics
+/// for the function declaractions and can be omitted if there is no generics.
+///
/// # Safety
///
/// Invoking this macro is only sound if the following code is already UB when the passed
/// the occasional mistake, and this check should help them figure things out.
#[allow_internal_unstable(const_eval_select)] // permit this to be called in stably-const fn
macro_rules! assert_unsafe_precondition {
- ($e:expr) => {
+ ($([$($tt:tt)*])?($($i:ident:$ty:ty),*$(,)?) => $e:expr) => {
if cfg!(debug_assertions) {
- // Use a closure so that we can capture arbitrary expressions from the invocation
- let runtime = || {
+ // allow non_snake_case to allow capturing const generics
+ #[allow(non_snake_case)]
+ #[inline(always)]
+ fn runtime$(<$($tt)*>)?($($i:$ty),*) {
if !$e {
// abort instead of panicking to reduce impact on code size
::core::intrinsics::abort();
}
- };
- const fn comptime() {}
+ }
+ #[allow(non_snake_case)]
+ const fn comptime$(<$($tt)*>)?($(_:$ty),*) {}
- ::core::intrinsics::const_eval_select((), comptime, runtime);
+ ::core::intrinsics::const_eval_select(($($i,)*), comptime, runtime);
}
};
}
// SAFETY: the safety contract for `copy_nonoverlapping` must be
// upheld by the caller.
unsafe {
- assert_unsafe_precondition!(
+ assert_unsafe_precondition!([T](src: *const T, dst: *mut T, count: usize) =>
is_aligned_and_not_null(src)
&& is_aligned_and_not_null(dst)
&& is_nonoverlapping(src, dst, count)
// SAFETY: the safety contract for `copy` must be upheld by the caller.
unsafe {
- assert_unsafe_precondition!(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!([T](src: *const T, dst: *mut T) =>
+ is_aligned_and_not_null(src) && is_aligned_and_not_null(dst));
copy(src, dst, count)
}
}
// SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
unsafe {
- assert_unsafe_precondition!(is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst));
write_bytes(dst, val, count)
}
}
-/// Selects which function to call depending on the context.
-///
-/// If this function is evaluated at compile-time, then a call to this
-/// intrinsic will be replaced with a call to `called_in_const`. It gets
-/// replaced with a call to `called_at_rt` otherwise.
-///
-/// # Type Requirements
-///
-/// The two functions must be both function items. They cannot be function
-/// pointers or closures.
-///
-/// `arg` will be the arguments that will be passed to either one of the
-/// two functions, therefore, both functions must accept the same type of
-/// arguments. Both functions must return RET.
-///
-/// # Safety
-///
-/// The two functions must behave observably equivalent. Safe code in other
-/// crates may assume that calling a `const fn` at compile-time and at run-time
-/// produces the same result. A function that produces a different result when
-/// evaluated at run-time, or has any other observable side-effects, is
-/// *unsound*.
-///
-/// Here is an example of how this could cause a problem:
-/// ```no_run
-/// #![feature(const_eval_select)]
-/// #![feature(core_intrinsics)]
-/// use std::hint::unreachable_unchecked;
-/// use std::intrinsics::const_eval_select;
-///
-/// // Crate A
-/// pub const fn inconsistent() -> i32 {
-/// fn runtime() -> i32 { 1 }
-/// const fn compiletime() -> i32 { 2 }
-///
-/// unsafe {
-// // ⚠ This code violates the required equivalence of `compiletime`
-/// // and `runtime`.
-/// const_eval_select((), compiletime, runtime)
-/// }
-/// }
-///
-/// // Crate B
-/// const X: i32 = inconsistent();
-/// let x = inconsistent();
-/// if x != X { unsafe { unreachable_unchecked(); }}
-/// ```
-///
-/// This code causes Undefined Behavior when being run, since the
-/// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
-/// which violates the principle that a `const fn` must behave the same at
-/// compile-time and at run-time. The unsafe code in crate B is fine.
+#[cfg(bootstrap)]
#[unstable(
feature = "const_eval_select",
issue = "none",
called_at_rt.call_once(arg)
}
+#[cfg(bootstrap)]
#[unstable(
feature = "const_eval_select",
issue = "none",
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![allow(explicit_outlives_requirements)]
+#![allow(incomplete_features)]
//
// Library features:
#![feature(const_align_offset)]
#![feature(const_type_id)]
#![feature(const_type_name)]
#![feature(const_default_impls)]
+#![feature(const_unicode_case_lookup)]
#![feature(const_unsafecell_get_mut)]
#![feature(core_panic)]
#![feature(duration_consts_float)]
//
// Language features:
#![feature(abi_unadjusted)]
+#![feature(adt_const_params)]
#![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)]
#![feature(associated_type_bounds)]
/// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`,
/// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied.
#[unstable(feature = "transmutability", issue = "99571")]
-#[lang = "transmute_trait"]
+#[cfg_attr(not(bootstrap), lang = "transmute_trait")]
#[rustc_on_unimplemented(
message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.",
label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`."
)]
-pub unsafe trait BikeshedIntrinsicFrom<
- Src,
- Context,
- const ASSUME_ALIGNMENT: bool,
- const ASSUME_LIFETIMES: bool,
- const ASSUME_VALIDITY: bool,
- const ASSUME_VISIBILITY: bool,
-> where
+pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }>
+where
Src: ?Sized,
{
}
/// What transmutation safety conditions shall the compiler assume that *you* are checking?
#[unstable(feature = "transmutability", issue = "99571")]
+#[cfg_attr(not(bootstrap), lang = "transmute_opts")]
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct Assume {
/// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that
/// that violates Rust's memory model.
pub lifetimes: bool,
+ /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the
+ /// type and field privacy of the destination type (and sometimes of the source type, too).
+ pub safety: bool,
+
/// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid
/// instance of the destination type.
pub validity: bool,
+}
- /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the
- /// type and field privacy of the destination type (and sometimes of the source type, too).
- pub visibility: bool,
+impl Assume {
+ /// Do not assume that *you* have ensured any safety properties are met.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const NOTHING: Self =
+ Self { alignment: false, lifetimes: false, safety: false, validity: false };
+
+ /// Assume only that alignment conditions are met.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const ALIGNMENT: Self = Self { alignment: true, ..Self::NOTHING };
+
+ /// Assume only that lifetime conditions are met.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const LIFETIMES: Self = Self { lifetimes: true, ..Self::NOTHING };
+
+ /// Assume only that safety conditions are met.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const SAFETY: Self = Self { safety: true, ..Self::NOTHING };
+
+ /// Assume only that dynamically-satisfiable validity conditions are met.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const VALIDITY: Self = Self { validity: true, ..Self::NOTHING };
+
+ /// Assume both `self` and `other_assumptions`.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const fn and(self, other_assumptions: Self) -> Self {
+ Self {
+ alignment: self.alignment || other_assumptions.alignment,
+ lifetimes: self.lifetimes || other_assumptions.lifetimes,
+ safety: self.safety || other_assumptions.safety,
+ validity: self.validity || other_assumptions.validity,
+ }
+ }
+
+ /// Assume `self`, excepting `other_assumptions`.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const fn but_not(self, other_assumptions: Self) -> Self {
+ Self {
+ alignment: self.alignment && !other_assumptions.alignment,
+ lifetimes: self.lifetimes && !other_assumptions.lifetimes,
+ safety: self.safety && !other_assumptions.safety,
+ validity: self.validity && !other_assumptions.validity,
+ }
+ }
+}
+
+// FIXME(jswrenn): This const op is not actually usable. Why?
+// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926
+#[unstable(feature = "transmutability", issue = "99571")]
+#[rustc_const_unstable(feature = "transmutability", issue = "99571")]
+impl const core::ops::Add for Assume {
+ type Output = Assume;
+
+ fn add(self, other_assumptions: Assume) -> Assume {
+ self.and(other_assumptions)
+ }
+}
+
+// FIXME(jswrenn): This const op is not actually usable. Why?
+// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926
+#[unstable(feature = "transmutability", issue = "99571")]
+#[rustc_const_unstable(feature = "transmutability", issue = "99571")]
+impl const core::ops::Sub for Assume {
+ type Output = Assume;
+
+ fn sub(self, other_assumptions: Assume) -> Assume {
+ self.but_not(other_assumptions)
+ }
}
#[inline]
pub(crate) const unsafe fn new_unchecked(align: usize) -> Self {
// SAFETY: Precondition passed to the caller.
- unsafe { assert_unsafe_precondition!(align.is_power_of_two()) };
+ unsafe { assert_unsafe_precondition!((align: usize) => align.is_power_of_two()) };
// SAFETY: By precondition, this must be a power of two, and
// our variants encompass all possible powers of two.
}
}
}
- // SAFETY: `u32` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- let rt_f32_to_u32 = |rt| unsafe { mem::transmute::<f32, u32>(rt) };
+
+ #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+ fn rt_f32_to_u32(x: f32) -> u32 {
+ // SAFETY: `u32` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ unsafe { mem::transmute(x) }
+ }
// SAFETY: We use internal implementations that either always work or fail at compile time.
unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
}
}
}
}
- // SAFETY: `u32` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- let rt_u32_to_f32 = |rt| unsafe { mem::transmute::<u32, f32>(rt) };
+
+ #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+ fn rt_u32_to_f32(x: u32) -> f32 {
+ // SAFETY: `u32` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ unsafe { mem::transmute(x) }
+ }
// SAFETY: We use internal implementations that either always work or fail at compile time.
unsafe { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) }
}
}
}
}
- // SAFETY: `u64` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- let rt_f64_to_u64 = |rt| unsafe { mem::transmute::<f64, u64>(rt) };
+
+ #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+ fn rt_f64_to_u64(rt: f64) -> u64 {
+ // SAFETY: `u64` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ unsafe { mem::transmute::<f64, u64>(rt) }
+ }
// SAFETY: We use internal implementations that either always work or fail at compile time.
unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
}
}
}
}
- // SAFETY: `u64` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- let rt_u64_to_f64 = |rt| unsafe { mem::transmute::<u64, f64>(rt) };
+
+ #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+ fn rt_u64_to_f64(rt: u64) -> f64 {
+ // SAFETY: `u64` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ unsafe { mem::transmute::<u64, f64>(rt) }
+ }
// SAFETY: We use internal implementations that either always work or fail at compile time.
unsafe { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) }
}
pub const unsafe fn new_unchecked(n: $Int) -> Self {
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
- core::intrinsics::assert_unsafe_precondition!(n != 0);
+ core::intrinsics::assert_unsafe_precondition!((n: $Int) => n != 0);
Self(n)
}
}
( $( $Ty: ident($Int: ident); )+ ) => {
$(
impl $Ty {
- /// Add an unsigned integer to a non-zero value.
- /// Check for overflow and return [`None`] on overflow
+ /// Adds an unsigned integer to a non-zero value.
+ /// Checks for overflow and returns [`None`] on overflow.
/// As a consequence, the result cannot wrap to zero.
///
///
}
}
- /// Add an unsigned integer to a non-zero value.
+ /// Adds an unsigned integer to a non-zero value.
#[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
///
/// # Examples
unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) }
}
- /// Add an unsigned integer to a non-zero value,
+ /// Adds an unsigned integer to a non-zero value,
/// assuming overflow cannot occur.
/// Overflow is unchecked, and it is undefined behaviour to overflow
/// *even if the result would wrap to a non-zero value*.
}
/// Returns the smallest power of two greater than or equal to n.
- /// Check for overflow and return [`None`]
+ /// Checks for overflow and returns [`None`]
/// if the next power of two is greater than the type’s maximum value.
/// As a consequence, the result cannot wrap to zero.
///
}
/// Checked absolute value.
- /// Check for overflow and returns [`None`] if
+ /// Checks for overflow and returns [`None`] if
#[doc = concat!("`self == ", stringify!($Int), "::MIN`.")]
/// The result cannot be zero.
///
( $( $signedness:ident $Ty: ident($Int: ty); )+ ) => {
$(
impl $Ty {
- /// Multiply two non-zero integers together.
- /// Check for overflow and return [`None`] on overflow.
+ /// Multiplies two non-zero integers together.
+ /// Checks for overflow and returns [`None`] on overflow.
/// As a consequence, the result cannot wrap to zero.
///
/// # Examples
}
}
- /// Multiply two non-zero integers together.
+ /// Multiplies two non-zero integers together.
#[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
///
/// # Examples
unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) }
}
- /// Multiply two non-zero integers together,
+ /// Multiplies two non-zero integers together,
/// assuming overflow cannot occur.
/// Overflow is unchecked, and it is undefined behaviour to overflow
/// *even if the result would wrap to a non-zero value*.
unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) }
}
- /// Raise non-zero value to an integer power.
- /// Check for overflow and return [`None`] on overflow.
+ /// Raises non-zero value to an integer power.
+ /// Checks for overflow and returns [`None`] on overflow.
/// As a consequence, the result cannot wrap to zero.
///
/// # Examples
impl<T> Bound<T> {
/// Converts from `&Bound<T>` to `Bound<&T>`.
#[inline]
- #[unstable(feature = "bound_as_ref", issue = "80996")]
+ #[stable(feature = "bound_as_ref_shared", since = "CURRENT_RUSTC_VERSION")]
pub fn as_ref(&self) -> Bound<&T> {
match *self {
Included(ref x) => Included(x),
/// Every `Try` type needs to be recreatable from its own associated
/// `Residual` type, but can also have additional `FromResidual` implementations
/// to support interconversion with other `Try` types.
-#[rustc_on_unimplemented(
+#[cfg_attr(not(bootstrap), rustc_on_unimplemented(
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::result::Result<T, E>",
+ R = "std::option::Option<std::convert::Infallible>"
+ ),
+ message = "the `?` operator can only be used on `Result`s, not `Option`s, \
+ in {ItemContext} that returns `Result`",
+ label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`",
+ parent_label = "this function returns a `Result`"
+ ),
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::result::Result<T, E>",
+ ),
+ // There's a special error message in the trait selection code for
+ // `From` in `?`, so this is not shown for result-in-result errors,
+ // and thus it can be phrased more strongly than `ControlFlow`'s.
+ message = "the `?` operator can only be used on `Result`s \
+ in {ItemContext} that returns `Result`",
+ label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+ parent_label = "this function returns a `Result`"
+ ),
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::option::Option<T>",
+ R = "std::result::Result<T, E>",
+ ),
+ message = "the `?` operator can only be used on `Option`s, not `Result`s, \
+ in {ItemContext} that returns `Option`",
+ label = "use `.ok()?` if you want to discard the `{R}` error information",
+ parent_label = "this function returns an `Option`"
+ ),
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::option::Option<T>",
+ ),
+ // `Option`-in-`Option` always works, as there's only one possible
+ // residual, so this can also be phrased strongly.
+ message = "the `?` operator can only be used on `Option`s \
+ in {ItemContext} that returns `Option`",
+ label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+ parent_label = "this function returns an `Option`"
+ ),
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::ops::ControlFlow<B, C>",
+ R = "std::ops::ControlFlow<B, C>",
+ ),
+ message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
+ can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
+ label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+ parent_label = "this function returns a `ControlFlow`",
+ note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
+ ),
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::ops::ControlFlow<B, C>",
+ // `R` is not a `ControlFlow`, as that case was matched previously
+ ),
+ message = "the `?` operator can only be used on `ControlFlow`s \
+ in {ItemContext} that returns `ControlFlow`",
+ label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+ parent_label = "this function returns a `ControlFlow`",
+ ),
+ on(
+ all(from_desugaring = "QuestionMark"),
+ message = "the `?` operator can only be used in {ItemContext} \
+ that returns `Result` or `Option` \
+ (or another type that implements `{FromResidual}`)",
+ label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
+ parent_label = "this function should return `Result` or `Option` to accept `?`"
+ ),
+))]
+#[cfg_attr(bootstrap, rustc_on_unimplemented(
on(
all(
from_desugaring = "QuestionMark",
label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
),
-)]
+))]
#[rustc_diagnostic_item = "FromResidual"]
#[unstable(feature = "try_trait_v2", issue = "84277")]
pub trait FromResidual<R = <Self as Try>::Residual> {
where
T: Sized,
{
+ let this = self;
// SAFETY: The comparison has no side-effects, and the intrinsic
// does this check internally in the CTFE implementation.
- unsafe { assert_unsafe_precondition!(self >= origin) };
+ unsafe {
+ assert_unsafe_precondition!([T](this: *const T, origin: *const T) => this >= origin)
+ };
let pointee_size = mem::size_of::<T>();
assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
// SAFETY: the caller must guarantee that `x` and `y` are
// valid for writes and properly aligned.
unsafe {
- assert_unsafe_precondition!(
+ assert_unsafe_precondition!([T](x: *mut T, y: *mut T, count: usize) =>
is_aligned_and_not_null(x)
&& is_aligned_and_not_null(y)
&& is_nonoverlapping(x, y, count)
// and cannot overlap `src` since `dst` must point to a distinct
// allocated object.
unsafe {
- assert_unsafe_precondition!(is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst));
mem::swap(&mut *dst, &mut src); // cannot overlap
}
src
pub unsafe fn read_volatile<T>(src: *const T) -> T {
// SAFETY: the caller must uphold the safety contract for `volatile_load`.
unsafe {
- assert_unsafe_precondition!(is_aligned_and_not_null(src));
+ assert_unsafe_precondition!([T](src: *const T) => is_aligned_and_not_null(src));
intrinsics::volatile_load(src)
}
}
pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
// SAFETY: the caller must uphold the safety contract for `volatile_store`.
unsafe {
- assert_unsafe_precondition!(is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst));
intrinsics::volatile_store(dst, src);
}
}
}
// FIXME const-hack
+#[track_caller]
fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! {
panic!("range start index {index} out of range for slice of length {len}");
}
+#[track_caller]
const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
panic!("slice start index is out of range for slice");
}
}
// FIXME const-hack
+#[track_caller]
fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! {
panic!("range end index {index} out of range for slice of length {len}");
}
+#[track_caller]
const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
panic!("slice end index is out of range for slice");
}
}
// FIXME const-hack
+#[track_caller]
fn slice_index_order_fail_rt(index: usize, end: usize) -> ! {
panic!("slice index starts at {index} but ends at {end}");
}
+#[track_caller]
const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! {
panic!("slice index start is larger than end");
}
#[inline]
unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
+ let this = self;
// SAFETY: the caller guarantees that `slice` is not dangling, so it
// cannot be longer than `isize::MAX`. They also guarantee that
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
// so the call to `add` is safe.
unsafe {
- assert_unsafe_precondition!(self < slice.len());
+ assert_unsafe_precondition!([T](this: usize, slice: *const [T]) => this < slice.len());
slice.as_ptr().add(self)
}
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
+ let this = self;
// SAFETY: see comments for `get_unchecked` above.
unsafe {
- assert_unsafe_precondition!(self < slice.len());
+ assert_unsafe_precondition!([T](this: usize, slice: *mut [T]) => this < slice.len());
slice.as_mut_ptr().add(self)
}
}
#[inline]
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+ let this = ops::Range { start: self.start, end: self.end };
// SAFETY: the caller guarantees that `slice` is not dangling, so it
// cannot be longer than `isize::MAX`. They also guarantee that
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
// so the call to `add` is safe.
unsafe {
- assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len());
+ assert_unsafe_precondition!([T](this: ops::Range<usize>, slice: *const [T]) =>
+ this.end >= this.start && this.end <= slice.len());
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start)
}
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+ let this = ops::Range { start: self.start, end: self.end };
// SAFETY: see comments for `get_unchecked` above.
unsafe {
- assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len());
+ assert_unsafe_precondition!([T](this: ops::Range<usize>, slice: *mut [T]) =>
+ this.end >= this.start && this.end <= slice.len());
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
}
}
#[unstable(feature = "slice_swap_unchecked", issue = "88539")]
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
- let ptr = self.as_mut_ptr();
+ let this = self;
+ let ptr = this.as_mut_ptr();
// SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()`
unsafe {
- assert_unsafe_precondition!(a < self.len() && b < self.len());
+ assert_unsafe_precondition!([T](a: usize, b: usize, this: &mut [T]) => a < this.len() && b < this.len());
ptr::swap(ptr.add(a), ptr.add(b));
}
}
#[inline]
#[must_use]
pub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
+ let this = self;
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
let new_len = unsafe {
- assert_unsafe_precondition!(N != 0 && self.len() % N == 0);
+ assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0);
exact_div(self.len(), N)
};
// SAFETY: We cast a slice of `new_len * N` elements into
#[inline]
#[must_use]
pub unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
+ let this = &*self;
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
let new_len = unsafe {
- assert_unsafe_precondition!(N != 0 && self.len() % N == 0);
- exact_div(self.len(), N)
+ assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0);
+ exact_div(this.len(), N)
};
// SAFETY: We cast a slice of `new_len * N` elements into
// a slice of `new_len` many `N` elements chunks.
// `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference
// is fine.
unsafe {
- assert_unsafe_precondition!(mid <= len);
+ assert_unsafe_precondition!((mid: usize, len: usize) => mid <= len);
(from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid))
}
}
pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
// SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
unsafe {
- assert_unsafe_precondition!(
+ assert_unsafe_precondition!([T](data: *const T, len: usize) =>
is_aligned_and_not_null(data)
&& crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize
);
pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
// SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
unsafe {
- assert_unsafe_precondition!(
+ assert_unsafe_precondition!([T](data: *mut T, len: usize) =>
is_aligned_and_not_null(data)
&& crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize
);
}
}
+#[track_caller]
const fn slice_error_fail_ct(_: &str, _: usize, _: usize) -> ! {
panic!("failed to slice string");
}
+#[track_caller]
fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! {
const MAX_DISPLAY_LENGTH: usize = 256;
let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH);
///! This file is generated by src/tools/unicode-table-generator; do not edit manually!
+#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
#[inline(always)]
-fn bitset_search<
+const fn bitset_search<
const N: usize,
const CHUNK_SIZE: usize,
const N1: usize,
let bucket_idx = (needle / 64) as usize;
let chunk_map_idx = bucket_idx / CHUNK_SIZE;
let chunk_piece = bucket_idx % CHUNK_SIZE;
- let chunk_idx = if let Some(&v) = chunk_idx_map.get(chunk_map_idx) {
- v
+ // FIXME: const-hack: Revert to `slice::get` after `const_slice_index`
+ // feature stabilizes.
+ let chunk_idx = if chunk_map_idx < chunk_idx_map.len() {
+ chunk_idx_map[chunk_map_idx]
} else {
return false;
};
let idx = bitset_chunk_idx[chunk_idx as usize][chunk_piece] as usize;
- let word = if let Some(word) = bitset_canonical.get(idx) {
- *word
+ // FIXME: const-hack: Revert to `slice::get` after `const_slice_index`
+ // feature stabilizes.
+ let word = if idx < bitset_canonical.len() {
+ bitset_canonical[idx]
} else {
let (real_idx, mapping) = bitset_canonicalized[idx - bitset_canonical.len()];
let mut word = bitset_canonical[real_idx as usize];
#[rustfmt::skip]
pub mod lowercase {
- static BITSET_CHUNKS_MAP: [u8; 123] = [
+ const BITSET_CHUNKS_MAP: &'static [u8; 123] = &[
14, 17, 0, 0, 9, 0, 0, 12, 13, 10, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 4, 1, 0, 15, 0, 8, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0,
3, 0, 0, 7,
];
- static BITSET_INDEX_CHUNKS: [[u8; 16]; 19] = [
+ const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 19] = &[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 55, 0],
[16, 49, 2, 20, 66, 9, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[63, 39, 54, 12, 73, 61, 18, 1, 6, 62, 71, 19, 68, 69, 3, 44],
];
- static BITSET_CANONICAL: [u64; 55] = [
+ const BITSET_CANONICAL: &'static [u64; 55] = &[
0b0000000000000000000000000000000000000000000000000000000000000000,
0b1111111111111111110000000000000000000000000011111111111111111111,
0b1010101010101010101010101010101010101010101010101010100000000010,
0b1110011111111111111111111111111111111111111111110000000000000000,
0b1110101111000000000000000000000000001111111111111111111111111100,
];
- static BITSET_MAPPING: [(u8, u8); 20] = [
+ const BITSET_MAPPING: &'static [(u8, u8); 20] = &[
(0, 64), (1, 188), (1, 183), (1, 176), (1, 109), (1, 124), (1, 126), (1, 66), (1, 70),
(1, 77), (2, 146), (2, 144), (2, 83), (3, 12), (3, 6), (4, 156), (4, 78), (5, 187),
(6, 132), (7, 93),
];
- pub fn lookup(c: char) -> bool {
+ #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
+ pub const fn lookup(c: char) -> bool {
super::bitset_search(
c as u32,
&BITSET_CHUNKS_MAP,
#[rustfmt::skip]
pub mod uppercase {
- static BITSET_CHUNKS_MAP: [u8; 125] = [
+ const BITSET_CHUNKS_MAP: &'static [u8; 125] = &[
12, 15, 6, 6, 0, 6, 6, 2, 4, 11, 6, 16, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 5, 6, 14, 6, 10, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 13, 6, 6,
6, 6, 9, 6, 3,
];
- static BITSET_INDEX_CHUNKS: [[u8; 16]; 17] = [
+ const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 17] = &[
[43, 43, 5, 34, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 5, 1],
[43, 43, 5, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43],
[43, 43, 39, 43, 43, 43, 43, 43, 17, 17, 62, 17, 42, 29, 24, 23],
[57, 19, 2, 18, 10, 47, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43],
[57, 37, 17, 27, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43],
];
- static BITSET_CANONICAL: [u64; 43] = [
+ const BITSET_CANONICAL: &'static [u64; 43] = &[
0b0000011111111111111111111111111000000000000000000000000000000000,
0b0000000000111111111111111111111111111111111111111111111111111111,
0b0101010101010101010101010101010101010101010101010101010000000001,
0b1111011111111111000000000000000000000000000000000000000000000000,
0b1111111100000000111111110000000000111111000000001111111100000000,
];
- static BITSET_MAPPING: [(u8, u8); 25] = [
+ const BITSET_MAPPING: &'static [(u8, u8); 25] = &[
(0, 187), (0, 177), (0, 171), (0, 167), (0, 164), (0, 32), (0, 47), (0, 51), (0, 121),
(0, 117), (0, 109), (1, 150), (1, 148), (1, 142), (1, 134), (1, 131), (1, 64), (2, 164),
(2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171),
];
- pub fn lookup(c: char) -> bool {
+ #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
+ pub const fn lookup(c: char) -> bool {
super::bitset_search(
c as u32,
&BITSET_CHUNKS_MAP,
demand
.provide_ref::<String>(&self.some_string)
.provide_ref::<str>(&self.some_string)
- .provide_value::<String>(|| "bye".to_owned());
+ .provide_value_with::<String>(|| "bye".to_owned());
}
}
#![cfg_attr(feature = "as_crate", no_std)] // We are std!
-#![cfg_attr(
- feature = "as_crate",
- feature(platform_intrinsics),
- feature(portable_simd)
-)]
+#![cfg_attr(feature = "as_crate", feature(platform_intrinsics), feature(portable_simd))]
#[cfg(not(feature = "as_crate"))]
use core::simd;
#[cfg(feature = "as_crate")]
use super::*;
+use std::cell::Cell;
use std::marker::PhantomData;
// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`.
) -> Buffer;
}
+thread_local! {
+ /// While running a proc-macro with the same-thread executor, this flag will
+ /// be set, forcing nested proc-macro invocations (e.g. due to
+ /// `TokenStream::expand_expr`) to be run using a cross-thread executor.
+ ///
+ /// This is required as the thread-local state in the proc_macro client does
+ /// not handle being re-entered, and will invalidate all `Symbol`s when
+ /// entering a nested macro.
+ static ALREADY_RUNNING_SAME_THREAD: Cell<bool> = Cell::new(false);
+}
+
+/// Keep `ALREADY_RUNNING_SAME_THREAD` (see also its documentation)
+/// set to `true`, preventing same-thread reentrance.
+struct RunningSameThreadGuard(());
+
+impl RunningSameThreadGuard {
+ fn new() -> Self {
+ let already_running = ALREADY_RUNNING_SAME_THREAD.replace(true);
+ assert!(
+ !already_running,
+ "same-thread nesting (\"reentrance\") of proc macro executions is not supported"
+ );
+ RunningSameThreadGuard(())
+ }
+}
+
+impl Drop for RunningSameThreadGuard {
+ fn drop(&mut self) {
+ ALREADY_RUNNING_SAME_THREAD.set(false);
+ }
+}
+
pub struct MaybeCrossThread<P> {
cross_thread: bool,
marker: PhantomData<P>,
run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer,
force_show_panics: bool,
) -> Buffer {
- if self.cross_thread {
+ if self.cross_thread || ALREADY_RUNNING_SAME_THREAD.get() {
<CrossThread<P>>::new().run_bridge_and_client(
dispatcher,
input,
run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer,
force_show_panics: bool,
) -> Buffer {
+ let _guard = RunningSameThreadGuard::new();
+
let mut dispatch = |buf| dispatcher.dispatch(buf);
run_client(BridgeConfig {
/// The default memory allocator provided by the operating system.
///
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
-/// plus related functions.
+/// plus related functions. However, it is not valid to mix use of the backing
+/// system allocator with `System`, as this implementation may include extra
+/// work, such as to serve alignment requests greater than the alignment
+/// provided directly by the backing system allocator.
///
/// This type implements the `GlobalAlloc` trait and Rust programs by default
/// work as if they had this definition:
///
/// If the returned iterator is dropped before being fully consumed, it
/// drops the remaining elements. The returned iterator keeps a mutable
- /// borrow on the vector to optimize its implementation.
+ /// borrow on the set to optimize its implementation.
///
/// # Examples
///
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
use crate::time::SystemTime;
-/// A reference to an open file on the filesystem.
+/// An object providing access to an open file on the filesystem.
///
/// An instance of a `File` can be read and/or written depending on what options
/// it was opened with. Files also implement [`Seek`] to alter the logical cursor
use crate::cell::{Cell, RefCell};
use crate::fmt;
use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
-use crate::pin::Pin;
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sync::{Arc, Mutex, MutexGuard, OnceLock};
use crate::sys::stdio;
// FIXME: this should be LineWriter or BufWriter depending on the state of
// stdout (tty or not). Note that if this is not line buffered it
// should also flush-on-panic or some form of flush-on-abort.
- inner: Pin<&'static ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>,
+ inner: &'static ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>,
}
/// A locked reference to the [`Stdout`] handle.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
Stdout {
- inner: Pin::static_ref(&STDOUT).get_or_init_pin(
- || unsafe { ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))) },
- |mutex| unsafe { mutex.init() },
- ),
+ inner: STDOUT
+ .get_or_init(|| ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())))),
}
}
+// Flush the data and disable buffering during shutdown
+// by replacing the line writer by one with zero
+// buffering capacity.
pub fn cleanup() {
- if let Some(instance) = STDOUT.get() {
- // Flush the data and disable buffering during shutdown
- // by replacing the line writer by one with zero
- // buffering capacity.
+ let mut initialized = false;
+ let stdout = STDOUT.get_or_init(|| {
+ initialized = true;
+ ReentrantMutex::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw())))
+ });
+
+ if !initialized {
+ // The buffer was previously initialized, overwrite it here.
// We use try_lock() instead of lock(), because someone
// might have leaked a StdoutLock, which would
// otherwise cause a deadlock here.
- if let Some(lock) = Pin::static_ref(instance).try_lock() {
+ if let Some(lock) = stdout.try_lock() {
*lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw());
}
}
/// standard library or via raw Windows API calls, will fail.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stderr {
- inner: Pin<&'static ReentrantMutex<RefCell<StderrRaw>>>,
+ inner: &'static ReentrantMutex<RefCell<StderrRaw>>,
}
/// A locked reference to the [`Stderr`] handle.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr {
// Note that unlike `stdout()` we don't use `at_exit` here to register a
- // destructor. Stderr is not buffered , so there's no need to run a
+ // destructor. Stderr is not buffered, so there's no need to run a
// destructor for flushing the buffer
- static INSTANCE: OnceLock<ReentrantMutex<RefCell<StderrRaw>>> = OnceLock::new();
+ static INSTANCE: ReentrantMutex<RefCell<StderrRaw>> =
+ ReentrantMutex::new(RefCell::new(stderr_raw()));
- Stderr {
- inner: Pin::static_ref(&INSTANCE).get_or_init_pin(
- || unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) },
- |mutex| unsafe { mutex.init() },
- ),
- }
+ Stderr { inner: &INSTANCE }
}
impl Stderr {
/// otherwise. `label` identifies the stream in a panic message.
///
/// This function is used to print error messages, so it takes extra
-/// care to avoid causing a panic when `local_s` is unusable.
-/// For instance, if the TLS key for the local stream is
-/// already destroyed, or if the local stream is locked by another
-/// thread, it will just fall back to the global stream.
+/// care to avoid causing a panic when `OUTPUT_CAPTURE` is unusable.
+/// For instance, if the TLS key for output capturing is already destroyed, or
+/// if the local stream is in use by another thread, it will just fall back to
+/// the global stream.
///
/// However, if the actual I/O causes an error, this function does panic.
fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
#[cfg(target_os = "espidf")]
let cmd = libc::F_DUPFD;
- let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
+ // Avoid using file descriptors below 3 as they are used for stdio
+ let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
Ok(unsafe { OwnedFd::from_raw_fd(fd) })
}
// Runs before `main`.
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
+//
+// # The `sigpipe` parameter
+//
+// Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to
+// `SIG_IGN`. Applications have good reasons to want a different behavior
+// though, so there is a `#[unix_sigpipe = "..."]` attribute on `fn main()` that
+// can be used to select how `SIGPIPE` shall be setup (if changed at all) before
+// `fn main()` is called. See <https://github.com/rust-lang/rust/issues/97889>
+// for more info.
+//
+// The `sigpipe` parameter to this function gets its value via the code that
+// rustc generates to invoke `fn lang_start()`. The reason we have `sigpipe` for
+// all platforms and not only Unix, is because std is not allowed to have `cfg`
+// directives as this high level. See the module docs in
+// `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe`
+// has a value, but its value is ignored.
+//
+// Even though it is an `u8`, it only ever has 3 values. These are documented in
+// `compiler/rustc_session/src/config/sigpipe.rs`.
#[cfg_attr(test, allow(dead_code))]
-unsafe fn init(argc: isize, argv: *const *const u8) {
+unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
unsafe {
- sys::init(argc, argv);
+ sys::init(argc, argv, sigpipe);
let main_guard = sys::thread::guard::init();
// Next, set up the current Thread with the guard information we just
main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),
argc: isize,
argv: *const *const u8,
+ sigpipe: u8,
) -> Result<isize, !> {
use crate::{mem, panic};
let rt_abort = move |e| {
// prevent libstd from accidentally introducing a panic to these functions. Another is from
// user code from `main` or, more nefariously, as described in e.g. issue #86030.
// SAFETY: Only called once during runtime initialization.
- panic::catch_unwind(move || unsafe { init(argc, argv) }).map_err(rt_abort)?;
+ panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;
let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
.map_err(move |e| {
mem::forget(e);
main: fn() -> T,
argc: isize,
argv: *const *const u8,
+ #[cfg(not(bootstrap))] sigpipe: u8,
) -> isize {
let Ok(v) = lang_start_internal(
&move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(),
argc,
argv,
+ #[cfg(bootstrap)]
+ 2, // Temporary inlining of sigpipe::DEFAULT until bootstrap stops being special
+ #[cfg(not(bootstrap))]
+ sigpipe,
);
v
}
and cause Futures to not implement `Send`"]
#[stable(feature = "rust1", since = "1.0.0")]
#[clippy::has_significant_drop]
+#[cfg_attr(not(test), rustc_diagnostic_item = "MutexGuard")]
pub struct MutexGuard<'a, T: ?Sized + 'a> {
lock: &'a Mutex<T>,
poison: poison::Guard,
use crate::marker::PhantomData;
use crate::mem::MaybeUninit;
use crate::panic::{RefUnwindSafe, UnwindSafe};
-use crate::pin::Pin;
use crate::sync::Once;
/// A synchronization primitive which can be written to only once.
Ok(unsafe { self.get_unchecked() })
}
- /// Internal-only API that gets the contents of the cell, initializing it
- /// in two steps with `f` and `g` if the cell was empty.
- ///
- /// `f` is called to construct the value, which is then moved into the cell
- /// and given as a (pinned) mutable reference to `g` to finish
- /// initialization.
- ///
- /// This allows `g` to inspect an manipulate the value after it has been
- /// moved into its final place in the cell, but before the cell is
- /// considered initialized.
- ///
- /// # Panics
- ///
- /// If `f` or `g` panics, the panic is propagated to the caller, and the
- /// cell remains uninitialized.
- ///
- /// With the current implementation, if `g` panics, the value from `f` will
- /// not be dropped. This should probably be fixed if this is ever used for
- /// a type where this matters.
- ///
- /// It is an error to reentrantly initialize the cell from `f`. The exact
- /// outcome is unspecified. Current implementation deadlocks, but this may
- /// be changed to a panic in the future.
- pub(crate) fn get_or_init_pin<F, G>(self: Pin<&Self>, f: F, g: G) -> Pin<&T>
- where
- F: FnOnce() -> T,
- G: FnOnce(Pin<&mut T>),
- {
- if let Some(value) = self.get_ref().get() {
- // SAFETY: The inner value was already initialized, and will not be
- // moved anymore.
- return unsafe { Pin::new_unchecked(value) };
- }
-
- let slot = &self.value;
-
- // Ignore poisoning from other threads
- // If another thread panics, then we'll be able to run our closure
- self.once.call_once_force(|_| {
- let value = f();
- // SAFETY: We use the Once (self.once) to guarantee unique access
- // to the UnsafeCell (slot).
- let value: &mut T = unsafe { (&mut *slot.get()).write(value) };
- // SAFETY: The value has been written to its final place in
- // self.value. We do not to move it anymore, which we promise here
- // with a Pin<&mut T>.
- g(unsafe { Pin::new_unchecked(value) });
- });
-
- // SAFETY: The inner value has been initialized, and will not be moved
- // anymore.
- unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) }
- }
-
/// Consumes the `OnceLock`, returning the wrapped value. Returns
/// `None` if the cell was empty.
///
and cause Futures to not implement `Send`"]
#[stable(feature = "rust1", since = "1.0.0")]
#[clippy::has_significant_drop]
+#[cfg_attr(not(test), rustc_diagnostic_item = "RwLockReadGuard")]
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
// NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
// `Ref` argument doesn't hold immutability for its whole scope, only until it drops.
and cause Future's to not implement `Send`"]
#[stable(feature = "rust1", since = "1.0.0")]
#[clippy::has_significant_drop]
+#[cfg_attr(not(test), rustc_diagnostic_item = "RwLockWriteGuard")]
pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
lock: &'a RwLock<T>,
poison: poison::Guard,
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(argc: isize, argv: *const *const u8) {
+pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
let _ = net::init();
args::init(argc, argv);
}
Mutex { inner: Spinlock::new(MutexInner::new()) }
}
- #[inline]
- pub unsafe fn init(&mut self) {}
-
#[inline]
pub unsafe fn lock(&self) {
loop {
Mutex { mtx: SpinIdOnceCell::new() }
}
- pub unsafe fn init(&mut self) {
- // Initialize `self.mtx` eagerly
- let id = new_mtx().unwrap_or_else(|e| fail(e, &"acre_mtx"));
- unsafe { self.mtx.set_unchecked((id, ())) };
- }
-
/// Get the inner mutex's ID, which is lazily created.
fn raw(&self) -> abi::ID {
match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) {
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(argc: isize, argv: *const *const u8) {
+pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
unsafe {
args::init(argc, argv);
}
Mutex { inner: SpinMutex::new(WaitVariable::new(false)) }
}
- #[inline]
- pub unsafe fn init(&mut self) {}
-
#[inline]
pub unsafe fn lock(&self) {
let mut guard = self.inner.lock();
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
+pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
// SAFETY: must be called only once during runtime cleanup.
pub unsafe fn cleanup() {}
Mutex { futex: AtomicU32::new(UNLOCKED) }
}
- #[inline]
- pub unsafe fn init(&mut self) {}
-
#[inline]
pub unsafe fn try_lock(&self) -> bool {
let thread_self = zx_thread_self();
Self { futex: AtomicU32::new(0) }
}
- #[inline]
- pub unsafe fn init(&mut self) {}
-
#[inline]
pub unsafe fn try_lock(&self) -> bool {
self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok()
Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
}
#[inline]
- pub unsafe fn init(&mut self) {
+ unsafe fn init(&mut self) {
// Issue #33770
//
// A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have
pub mod time;
#[cfg(target_os = "espidf")]
-pub fn init(argc: isize, argv: *const *const u8) {}
+pub fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {}
#[cfg(not(target_os = "espidf"))]
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(argc: isize, argv: *const *const u8) {
+// See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`.
+pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
// The standard streams might be closed on application startup. To prevent
// std::io::{stdin, stdout,stderr} objects from using other unrelated file
// resources opened later, we reopen standards streams when they are closed.
// want!
//
// Hence, we set SIGPIPE to ignore when the program starts up in order
- // to prevent this problem.
- reset_sigpipe();
+ // to prevent this problem. Add `#[unix_sigpipe = "..."]` above `fn main()` to
+ // alter this behavior.
+ reset_sigpipe(sigpipe);
stack_overflow::init();
args::init(argc, argv);
}
}
- unsafe fn reset_sigpipe() {
+ unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) {
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))]
- rtassert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
+ {
+ // We don't want to add this as a public type to libstd, nor do we
+ // want to `include!` a file from the compiler (which would break
+ // Miri and xargo for example), so we choose to duplicate these
+ // constants from `compiler/rustc_session/src/config/sigpipe.rs`.
+ // See the other file for docs. NOTE: Make sure to keep them in
+ // sync!
+ mod sigpipe {
+ pub const INHERIT: u8 = 1;
+ pub const SIG_IGN: u8 = 2;
+ pub const SIG_DFL: u8 = 3;
+ }
+
+ let handler = match sigpipe {
+ sigpipe::INHERIT => None,
+ sigpipe::SIG_IGN => Some(libc::SIG_IGN),
+ sigpipe::SIG_DFL => Some(libc::SIG_DFL),
+ _ => unreachable!(),
+ };
+ if let Some(handler) = handler {
+ rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR);
+ }
+ }
}
}
Some(b"") => Cgroup::V2,
Some(controllers)
if from_utf8(controllers)
- .is_ok_and(|c| c.split(",").any(|c| c == "cpu")) =>
+ .is_ok_and(|c| c.split(',').any(|c| c == "cpu")) =>
{
Cgroup::V1
}
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
+pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
// SAFETY: must be called only once during runtime cleanup.
// NOTE: this is not guaranteed to run, for example when the program aborts.
Mutex { locked: Cell::new(false) }
}
- #[inline]
- pub unsafe fn init(&mut self) {}
-
#[inline]
pub unsafe fn lock(&self) {
assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex");
status >= 0
}
-pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002;
+pub const BCRYPT_RNG_ALG_HANDLE: usize = 0x81;
#[repr(C)]
pub struct UNICODE_STRING {
MaximumFileInfoByHandlesClass,
}
+#[repr(C)]
+pub struct FILE_ATTRIBUTE_TAG_INFO {
+ pub FileAttributes: DWORD,
+ pub ReparseTag: DWORD,
+}
+
#[repr(C)]
pub struct FILE_DISPOSITION_INFO {
pub DeleteFile: BOOLEAN,
cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?;
let mut reparse_tag = 0;
if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
- let mut b =
- Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
- if let Ok((_, buf)) = self.reparse_point(&mut b) {
- reparse_tag = (*buf).ReparseTag;
+ let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
+ cvt(c::GetFileInformationByHandleEx(
+ self.handle.as_raw_handle(),
+ c::FileAttributeTagInfo,
+ ptr::addr_of_mut!(attr_tag).cast(),
+ mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
+ ))?;
+ if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+ reparse_tag = attr_tag.ReparseTag;
}
}
Ok(FileAttr {
attr.file_size = info.AllocationSize as u64;
attr.number_of_links = Some(info.NumberOfLinks);
if attr.file_type().is_reparse_point() {
- let mut b =
- Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
- if let Ok((_, buf)) = self.reparse_point(&mut b) {
- attr.reparse_tag = (*buf).ReparseTag;
+ let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
+ cvt(c::GetFileInformationByHandleEx(
+ self.handle.as_raw_handle(),
+ c::FileAttributeTagInfo,
+ ptr::addr_of_mut!(attr_tag).cast(),
+ mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
+ ))?;
+ if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+ reparse_tag = attr_tag.ReparseTag;
}
}
Ok(attr)
pub const fn new() -> Mutex {
Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) }
}
- #[inline]
- pub unsafe fn init(&mut self) {}
#[inline]
pub unsafe fn lock(&self) {
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
stack_overflow::init();
// Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
+//! # Random key generation
+//!
+//! This module wraps the RNG provided by the OS. There are a few different
+//! ways to interface with the OS RNG so it's worth exploring each of the options.
+//! Note that at the time of writing these all go through the (undocumented)
+//! `bcryptPrimitives.dll` but they use different route to get there.
+//!
+//! Originally we were using [`RtlGenRandom`], however that function is
+//! deprecated and warns it "may be altered or unavailable in subsequent versions".
+//!
+//! So we switched to [`BCryptGenRandom`] with the `BCRYPT_USE_SYSTEM_PREFERRED_RNG`
+//! flag to query and find the system configured RNG. However, this change caused a small
+//! but significant number of users to experience panics caused by a failure of
+//! this function. See [#94098].
+//!
+//! The current version changes this to use the `BCRYPT_RNG_ALG_HANDLE`
+//! [Pseudo-handle], which gets the default RNG algorithm without querying the
+//! system preference thus hopefully avoiding the previous issue.
+//! This is only supported on Windows 10+ so a fallback is used for older versions.
+//!
+//! [#94098]: https://github.com/rust-lang/rust/issues/94098
+//! [`RtlGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
+//! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
+//! [Pseudo-handle]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles
use crate::io;
use crate::mem;
use crate::ptr;
use crate::sys::c;
+/// Generates high quality secure random keys for use by [`HashMap`].
+///
+/// This is used to seed the default [`RandomState`].
+///
+/// [`HashMap`]: crate::collections::HashMap
+/// [`RandomState`]: crate::collections::hash_map::RandomState
pub fn hashmap_random_keys() -> (u64, u64) {
let mut v = (0, 0);
let ret = unsafe {
+ let size = mem::size_of_val(&v).try_into().unwrap();
c::BCryptGenRandom(
- ptr::null_mut(),
- &mut v as *mut _ as *mut u8,
- mem::size_of_val(&v) as c::ULONG,
- c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
+ // BCRYPT_RNG_ALG_HANDLE is only supported in Windows 10+.
+ // So for Windows 8.1 and Windows 7 we'll need a fallback when this fails.
+ ptr::invalid_mut(c::BCRYPT_RNG_ALG_HANDLE),
+ ptr::addr_of_mut!(v).cast(),
+ size,
+ 0,
)
};
if ret != 0 { fallback_rng() } else { v }
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
+use super::mutex as sys;
use crate::cell::UnsafeCell;
-use crate::marker::PhantomPinned;
use crate::ops::Deref;
use crate::panic::{RefUnwindSafe, UnwindSafe};
-use crate::pin::Pin;
use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
-use crate::sys::locks as sys;
/// A re-entrant mutual exclusion
///
/// synchronization is left to the mutex, making relaxed memory ordering for
/// the `owner` field fine in all cases.
pub struct ReentrantMutex<T> {
- mutex: sys::Mutex,
+ mutex: sys::MovableMutex,
owner: AtomicUsize,
lock_count: UnsafeCell<u32>,
data: T,
- _pinned: PhantomPinned,
}
unsafe impl<T: Send> Send for ReentrantMutex<T> {}
/// guarded data.
#[must_use = "if unused the ReentrantMutex will immediately unlock"]
pub struct ReentrantMutexGuard<'a, T: 'a> {
- lock: Pin<&'a ReentrantMutex<T>>,
+ lock: &'a ReentrantMutex<T>,
}
impl<T> !Send for ReentrantMutexGuard<'_, T> {}
impl<T> ReentrantMutex<T> {
/// Creates a new reentrant mutex in an unlocked state.
- ///
- /// # Unsafety
- ///
- /// This function is unsafe because it is required that `init` is called
- /// once this mutex is in its final resting place, and only then are the
- /// lock/unlock methods safe.
- pub const unsafe fn new(t: T) -> ReentrantMutex<T> {
+ pub const fn new(t: T) -> ReentrantMutex<T> {
ReentrantMutex {
- mutex: sys::Mutex::new(),
+ mutex: sys::MovableMutex::new(),
owner: AtomicUsize::new(0),
lock_count: UnsafeCell::new(0),
data: t,
- _pinned: PhantomPinned,
}
}
- /// Initializes this mutex so it's ready for use.
- ///
- /// # Unsafety
- ///
- /// Unsafe to call more than once, and must be called after this will no
- /// longer move in memory.
- pub unsafe fn init(self: Pin<&mut Self>) {
- self.get_unchecked_mut().mutex.init()
- }
-
/// Acquires a mutex, blocking the current thread until it is able to do so.
///
/// This function will block the caller until it is available to acquire the mutex.
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return failure if the mutex would otherwise be
/// acquired.
- pub fn lock(self: Pin<&Self>) -> ReentrantMutexGuard<'_, T> {
+ pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
let this_thread = current_thread_unique_ptr();
- // Safety: We only touch lock_count when we own the lock,
- // and since self is pinned we can safely call the lock() on the mutex.
+ // Safety: We only touch lock_count when we own the lock.
unsafe {
if self.owner.load(Relaxed) == this_thread {
self.increment_lock_count();
} else {
- self.mutex.lock();
+ self.mutex.raw_lock();
self.owner.store(this_thread, Relaxed);
debug_assert_eq!(*self.lock_count.get(), 0);
*self.lock_count.get() = 1;
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return failure if the mutex would otherwise be
/// acquired.
- pub fn try_lock(self: Pin<&Self>) -> Option<ReentrantMutexGuard<'_, T>> {
+ pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> {
let this_thread = current_thread_unique_ptr();
- // Safety: We only touch lock_count when we own the lock,
- // and since self is pinned we can safely call the try_lock on the mutex.
+ // Safety: We only touch lock_count when we own the lock.
unsafe {
if self.owner.load(Relaxed) == this_thread {
self.increment_lock_count();
impl<T> Drop for ReentrantMutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
- // Safety: We own the lock, and the lock is pinned.
+ // Safety: We own the lock.
unsafe {
*self.lock.lock_count.get() -= 1;
if *self.lock.lock_count.get() == 0 {
self.lock.owner.store(0, Relaxed);
- self.lock.mutex.unlock();
+ self.lock.mutex.raw_unlock();
}
}
}
-use crate::boxed::Box;
use crate::cell::RefCell;
-use crate::pin::Pin;
use crate::sync::Arc;
use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
use crate::thread;
#[test]
fn smoke() {
- let m = unsafe {
- let mut m = Box::pin(ReentrantMutex::new(()));
- m.as_mut().init();
- m
- };
- let m = m.as_ref();
+ let m = ReentrantMutex::new(());
{
let a = m.lock();
{
#[test]
fn is_mutex() {
- let m = unsafe {
- // FIXME: Simplify this if Arc gets an Arc::get_pin_mut.
- let mut m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
- Pin::new_unchecked(Arc::get_mut_unchecked(&mut m)).init();
- Pin::new_unchecked(m)
- };
+ let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
let m2 = m.clone();
- let lock = m.as_ref().lock();
+ let lock = m.lock();
let child = thread::spawn(move || {
- let lock = m2.as_ref().lock();
+ let lock = m2.lock();
assert_eq!(*lock.borrow(), 4950);
});
for i in 0..100 {
- let lock = m.as_ref().lock();
+ let lock = m.lock();
*lock.borrow_mut() += i;
}
drop(lock);
#[test]
fn trylock_works() {
- let m = unsafe {
- // FIXME: Simplify this if Arc gets an Arc::get_pin_mut.
- let mut m = Arc::new(ReentrantMutex::new(()));
- Pin::new_unchecked(Arc::get_mut_unchecked(&mut m)).init();
- Pin::new_unchecked(m)
- };
+ let m = Arc::new(ReentrantMutex::new(()));
let m2 = m.clone();
- let _lock = m.as_ref().try_lock();
- let _lock2 = m.as_ref().try_lock();
+ let _lock = m.try_lock();
+ let _lock2 = m.try_lock();
thread::spawn(move || {
- let lock = m2.as_ref().try_lock();
+ let lock = m2.try_lock();
assert!(lock.is_none());
})
.join()
.unwrap();
- let _lock3 = m.as_ref().try_lock();
+ let _lock3 = m.try_lock();
}
pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
def check_vendored_status(self):
"""Check that vendoring is configured properly"""
+ # keep this consistent with the equivalent check in rustbuild:
+ # https://github.com/rust-lang/rust/blob/a8a33cf27166d3eabaffc58ed3799e054af3b0c6/src/bootstrap/lib.rs#L399-L405
if 'SUDO_USER' in os.environ and not self.use_vendored_sources:
if os.getuid() == 0:
self.use_vendored_sources = True
compiler: build_compiler,
target: target_compiler.host,
});
- builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe("ld", target_compiler.host)));
+ for name in crate::LLD_FILE_NAMES {
+ builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe(name, target_compiler.host)));
+ }
}
if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
pub struct Target {
/// Some(path to llvm-config) if using an external LLVM.
pub llvm_config: Option<PathBuf>,
+ pub llvm_has_rust_patches: Option<bool>,
/// Some(path to FileCheck) if one was specified.
pub llvm_filecheck: Option<PathBuf>,
pub llvm_libunwind: Option<LlvmLibunwind>,
default_linker: Option<PathBuf> = "default-linker",
linker: Option<String> = "linker",
llvm_config: Option<String> = "llvm-config",
+ llvm_has_rust_patches: Option<bool> = "llvm-has-rust-patches",
llvm_filecheck: Option<String> = "llvm-filecheck",
llvm_libunwind: Option<String> = "llvm-libunwind",
android_ndk: Option<String> = "android-ndk",
if let Some(ref s) = cfg.llvm_config {
target.llvm_config = Some(config.src.join(s));
}
+ target.llvm_has_rust_patches = cfg.llvm_has_rust_patches;
if let Some(ref s) = cfg.llvm_filecheck {
target.llvm_filecheck = Some(config.src.join(s));
}
let gcc_lld_src_dir = src_dir.join("gcc-ld");
let gcc_lld_dst_dir = dst_dir.join("gcc-ld");
t!(fs::create_dir(&gcc_lld_dst_dir));
- let exe_name = exe("ld", compiler.host);
- builder.copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name));
+ for name in crate::LLD_FILE_NAMES {
+ let exe_name = exe(name, compiler.host);
+ builder
+ .copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name));
+ }
}
// Man pages
t!(fs::create_dir_all(&out));
let mut index = tool::ErrorIndex::command(builder);
index.arg("html");
- index.arg(out.join("error-index.html"));
+ index.arg(out);
index.arg(&builder.version);
builder.run(&mut index);
use std::process::Command;
use std::str;
+use config::Target;
use filetime::FileTime;
use once_cell::sync::OnceCell;
"opt", // used to optimize LLVM bytecode
];
+/// LLD file names for all flavors.
+const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"];
+
pub const VERSION: usize = 2;
/// Extra --check-cfg to add when building
let src = config.src.clone();
let out = config.out.clone();
+ #[cfg(unix)]
+ // keep this consistent with the equivalent check in x.py:
+ // https://github.com/rust-lang/rust/blob/a8a33cf27166d3eabaffc58ed3799e054af3b0c6/src/bootstrap/bootstrap.py#L796-L797
let is_sudo = match env::var_os("SUDO_USER") {
- Some(sudo_user) => match env::var_os("USER") {
- Some(user) => user != sudo_user,
- None => false,
- },
+ Some(_sudo_user) => {
+ let uid = unsafe { libc::getuid() };
+ uid == 0
+ }
None => false,
};
+ #[cfg(not(unix))]
+ let is_sudo = false;
let ignore_git = config.ignore_git;
let rust_info = channel::GitInfo::new(ignore_git, &src);
///
/// If no custom `llvm-config` was specified then Rust's llvm will be used.
fn is_rust_llvm(&self, target: TargetSelection) -> bool {
- if self.config.llvm_from_ci && target == self.config.build {
- return true;
- }
-
match self.config.target_config.get(&target) {
- Some(ref c) => c.llvm_config.is_none(),
+ Some(Target { llvm_has_rust_patches: Some(patched), .. }) => *patched,
+ Some(Target { llvm_config, .. }) => {
+ // If the user set llvm-config we assume Rust is not patched,
+ // but first check to see if it was configured by llvm-from-ci.
+ (self.config.llvm_from_ci && target == self.config.build) || llvm_config.is_none()
+ }
None => true,
}
}
.output()
.map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
.unwrap_or(String::new());
- lines.lines().find_map(|l| l.split(":browser-ui-test@").skip(1).next()).map(|v| v.to_owned())
+ lines
+ .lines()
+ .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
+ .map(|v| v.to_owned())
}
fn get_browser_ui_test_version(npm: &Path) -> Option<String> {
-FROM ubuntu:16.04
+FROM ubuntu:22.04
+ARG DEBIAN_FRONTEND=noninteractive
COPY scripts/android-base-apt-get.sh /scripts/
RUN sh /scripts/android-base-apt-get.sh
libgl1-mesa-glx \
libpulse0 \
libstdc++6:i386 \
- openjdk-9-jre-headless \
+ openjdk-8-jre-headless \
tzdata \
wget \
python3
ENV TARGETS=arm-linux-androideabi
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
-ENV NO_DOWNLOAD_CI_LLVM 1
-
-ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14 \
- --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14
ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
COPY scripts/android-start-emulator.sh /scripts/
ENTRYPOINT ["/scripts/android-start-emulator.sh"]
-FROM ubuntu:16.04
+FROM ubuntu:22.04
COPY scripts/android-base-apt-get.sh /scripts/
RUN sh /scripts/android-base-apt-get.sh
--i686-linux-android-ndk=/android/ndk/x86-14 \
--aarch64-linux-android-ndk=/android/ndk/arm64-21 \
--x86_64-linux-android-ndk=/android/ndk/x86_64-21 \
- --disable-docs \
- --set llvm.allow-old-toolchain
+ --disable-docs
ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-FROM ubuntu:16.04
+FROM ubuntu:22.04
+ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
g++-multilib \
make \
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
RUN mkdir -p /config
RUN echo "[rust]" > /config/nopt-std-config.toml
RUN echo "optimize = false" >> /config/nopt-std-config.toml
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
-ENV NO_DOWNLOAD_CI_LLVM 1
-
-ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests \
- --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \
&& python3 ../x.py --stage 2 test
-FROM ubuntu:16.04
+FROM ubuntu:22.04
+ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
g++-multilib \
make \
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
-ENV NO_DOWNLOAD_CI_LLVM 1
-ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu \
- --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu
# Exclude some tests that are unlikely to be platform specific, to speed up
# this slow job.
ENV SCRIPT python3 ../x.py --stage 2 test \
python3 ../x.py test --stage 0 src/tools/compiletest && \
python3 ../x.py test --stage 2 src/tools/tidy && \
python3 ../x.py test --stage 0 core alloc std test proc_macro && \
- python3 ../x.py doc --stage 0 library/test && \
+ # Build both public and internal documentation.
+ RUSTDOCFLAGS="--document-private-items" python3 ../x.py doc --stage 0 library/test && \
/scripts/validate-toolstate.sh && \
/scripts/validate-error-codes.sh && \
reuse lint && \
-FROM ubuntu:16.04
+FROM ubuntu:22.04
+ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
-ENV NO_DOWNLOAD_CI_LLVM 1
-
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \
- --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
ENV RUST_CHECK_TARGET check-aux
-FROM ubuntu:16.04
+FROM ubuntu:22.04
+ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
+# We are disabling CI LLVM since distcheck is an offline build.
ENV NO_DOWNLOAD_CI_LLVM 1
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false \
- --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false
ENV SCRIPT python3 ../x.py --stage 2 test distcheck
ENV DIST_SRC 1
-FROM ubuntu:16.04
+FROM ubuntu:22.04
+ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
libdbus-1-3 \
libexpat1 \
libfontconfig1 \
+ libgbm1 \
libgcc1 \
libgconf-2-4 \
libgdk-pixbuf2.0-0 \
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
COPY host-x86_64/x86_64-gnu-tools/checktools.sh /tmp/
-RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
-ENV NODE_FOLDER=/node-v14.4.0-linux-x64/bin
+RUN curl -sL https://nodejs.org/dist/v14.20.0/node-v14.20.0-linux-x64.tar.xz | tar -xJ
+ENV NODE_FOLDER=/node-v14.20.0-linux-x64/bin
ENV PATH="$NODE_FOLDER:${PATH}"
COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/
# the local version of the package is different than the one used by the CI.
RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
-ENV NO_DOWNLOAD_CI_LLVM 1
-
ENV RUST_CONFIGURE_ARGS \
- --set llvm.allow-old-toolchain \
--build=x86_64-unknown-linux-gnu \
--save-toolstates=/tmp/toolstate/toolstates.json
ENV SCRIPT /tmp/checktools.sh ../x.py && \
- NODE_PATH=`npm root -g` python3 ../x.py test src/test/rustdoc-gui --stage 2
+ NODE_PATH=`npm root -g` python3 ../x.py test src/test/rustdoc-gui --stage 2 \
+ --test-args "'--no-sandbox --jobs 1'"
g++ \
git \
libssl-dev \
+ libncurses5 \
make \
ninja-build \
pkg-config \
--- /dev/null
+# armv4t-none-eabi
+
+Tier 3
+
+Bare-metal target for any cpu in the ARMv4T architecture family, supporting
+ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code
+generation.
+
+In particular this supports the Gameboy Advance (GBA), but there's nothing GBA
+specific with this target, so any ARMv4T device should work fine.
+
+## Target Maintainers
+
+* [@Lokathor](https://github.com/lokathor)
+
+## Requirements
+
+The target is cross-compiled, and uses static linking.
+
+The linker that comes with rustc cannot link for this platform (the platform is
+too old). You will need the `arm-none-eabi-ld` linker from a GNU Binutils
+targeting ARM. This can be obtained for Windows/Mac/Linux from the [ARM
+Developer Website][arm-dev], or possibly from your OS's package manager.
+
+[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
+
+This target doesn't provide a linker script, you'll need to bring your own
+according to the specific device you want to target. Pass
+`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
+`your_script.ld` during linking.
+
+## Building Rust Programs
+
+Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
+
+Just use the `build-std` nightly cargo feature to build the `core` library. You
+can pass this as a command line argument to cargo, or your `.cargo/config.toml`
+file might include the following lines:
+
+```toml
+[unstable]
+build-std = ["core"]
+```
+
+Most of `core` should work as expected, with the following notes:
+* the target is "soft float", so `f32` and `f64` operations are emulated in
+ software.
+* integer division is also emulated in software.
+* the target is old enough that it doesn't have atomic instructions.
+
+Rust programs are output as ELF files.
+
+For running on hardware, you'll generally need to extract the "raw" program code
+out of the ELF and into a file of its own. The `objcopy` program provided as
+part of the GNU Binutils can do this:
+
+```shell
+arm-none-eabi-objcopy --output-target binary [in_file] [out_file]
+```
+
+## Testing
+
+This is a cross-compiled target that you will need to emulate during testing.
+
+Because this is a device-agnostic target, and the exact emulator that you'll
+need depends on the specific device you want to run your code on.
+
+For example, when programming for the Gameboy Advance, the
+[mgba-test-runner](https://github.com/agbrs/agb) program could be used to make a
+normal set of rust tests be run within the `mgba` emulator.
+++ /dev/null
-# armv4t-none-eabi
-
-Tier 3
-
-Bare-metal target for any cpu in the ARMv4T architecture family, supporting
-ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code
-generation.
-
-In particular this supports the Gameboy Advance (GBA), but there's nothing GBA
-specific with this target, so any ARMv4T device should work fine.
-
-## Target Maintainers
-
-* [@Lokathor](https://github.com/lokathor)
-
-## Requirements
-
-The target is cross-compiled, and uses static linking.
-
-The linker that comes with rustc cannot link for this platform (the platform is
-too old). You will need the `arm-none-eabi-ld` linker from a GNU Binutils
-targeting ARM. This can be obtained for Windows/Mac/Linux from the [ARM
-Developer Website][arm-dev], or possibly from your OS's package manager.
-
-[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
-
-This target doesn't provide a linker script, you'll need to bring your own
-according to the specific device you want to target. Pass
-`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
-`your_script.ld` during linking.
-
-## Building Rust Programs
-
-Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
-
-Just use the `build-std` nightly cargo feature to build the `core` library. You
-can pass this as a command line argument to cargo, or your `.cargo/config.toml`
-file might include the following lines:
-
-```toml
-[unstable]
-build-std = ["core"]
-```
-
-Most of `core` should work as expected, with the following notes:
-* the target is "soft float", so `f32` and `f64` operations are emulated in
- software.
-* integer division is also emulated in software.
-* the target is old enough that it doesn't have atomic instructions.
-
-Rust programs are output as ELF files.
-
-For running on hardware, you'll generally need to extract the "raw" program code
-out of the ELF and into a file of its own. The `objcopy` program provided as
-part of the GNU Binutils can do this:
-
-```shell
-arm-none-eabi-objcopy --output-target binary [in_file] [out_file]
-```
-
-## Testing
-
-This is a cross-compiled target that you will need to emulate during testing.
-
-Because this is a device-agnostic target, and the exact emulator that you'll
-need depends on the specific device you want to run your code on.
-
-For example, when programming for the Gameboy Advance, the
-[mgba-test-runner](https://github.com/agbrs/agb) program could be used to make a
-normal set of rust tests be run within the `mgba` emulator.
```sh
rustup target add x86_64-fuchsia
-rustup target add aarch_64-fuchsia
+rustup target add aarch64-fuchsia
```
After installing our Fuchsia targets, we can now compile a Rust binary that targets
[target.x86_64-fuchsia]
rustflags = [
- "-Lnative", "<SDK_PATH>/arch/x64/sysroot/lib",
- "-Lnative", "<SDK_PATH>/arch/x64/lib"
+ "-Lnative=<SDK_PATH>/arch/x64/lib",
+ "-Lnative=<SDK_PATH>/arch/x64/sysroot/lib"
]
```
*Note: Make sure to fill out `<SDK_PATH>` with the path to the downloaded [Fuchsia SDK].*
+These options configure the following:
+
+* `-Lnative=${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from
+ the SDK
+* `-Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia kernel
+ libraries from the SDK
+
In total, our new project will look like:
**Current directory structure**
The `package` file describes our package's name and version number. Every
package must contain one.
-**`pkg/hello_fuchsia.manifest`**
+**`pkg/hello_fuchsia.manifest` if using cargo**
+```txt
+bin/hello_fuchsia=target/x86_64-fuchsia/debug/hello_fuchsia
+lib/ld.so.1=<SDK_PATH>/arch/x64/sysroot/dist/lib/ld.so.1
+lib/libfdio.so=<SDK_PATH>/arch/x64/dist/libfdio.so
+meta/package=pkg/meta/package
+meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm
+```
+
+**`pkg/hello_fuchsia.manifest` if using rustc**
```txt
-bin/hello_fuchsia=target/x86_64-fuchsia/debug/hello_fuchsia # If using cargo...
-bin/hello_fuchsia=bin/hello_fuchsia # If using rustc...
+bin/hello_fuchsia=bin/hello_fuchsia
lib/ld.so.1=<SDK_PATH>/arch/x64/sysroot/dist/lib/ld.so.1
lib/libfdio.so=<SDK_PATH>/arch/x64/dist/libfdio.so
meta/package=pkg/meta/package
}
```
+**Current directory structure**
```txt
hello_fuchsia/
┗━ pkg/
-o pkg/meta/hello_fuchsia.cm
```
+*Note: `--includepath` tells the compiler where to look for `include`s from our CML.
+In our case, we're only using `syslog/client.shard.cml`.*
+
**Current directory structure**
```txt
hello_fuchsia/
┗━ hello_fuchsia.cml
```
-*Note: `--includepath` tells the compiler where to look for `include`s from our CML.
-In our case, we're only using `syslog/client.shard.cml`.*
-
### Building a Fuchsia package
Next, we'll build a package manifest as defined by our manifest:
```sh
${SDK_PATH}/tools/${ARCH}/pm \
- -o hello_fuchsia_manifest \
+ -o pkg/hello_fuchsia_manifest \
-m pkg/hello_fuchsia.manifest \
build \
- -output-package-manifest hello_fuchsia_package_manifest
+ -output-package-manifest pkg/hello_fuchsia_package_manifest
```
This will produce `pkg/hello_fuchsia_manifest/` which is a package manifest we can
```sh
${SDK_PATH}/tools/${ARCH}/pm publish \
- -repo repo \
- -lp -f <(echo "hello_fuchsia_package_manifest")
+ -repo pkg/repo \
+ -lp -f <(echo "pkg/hello_fuchsia_package_manifest")
```
Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using:
```sh
${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \
- repo \
+ pkg/repo \
-r hello-fuchsia
```
```sh
${SDK_PATH}/tools/${ARCH}/ffx component run \
+ /core/ffx-laboratory:hello_fuchsia \
fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm
```
```sh
${SDK_PATH}/tools/${ARCH}/ffx component run \
--recreate \
+ /core/ffx-laboratory:hello_fuchsia \
fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm
```
--- /dev/null
+# `unix_sigpipe`
+
+The tracking issue for this feature is: [#97889]
+
+[#97889]: https://github.com/rust-lang/rust/issues/97889
+
+---
+
+The `#[unix_sigpipe = "..."]` attribute on `fn main()` can be used to specify how libstd shall setup `SIGPIPE` on Unix platforms before invoking `fn main()`. This attribute is ignored on non-Unix targets. There are three variants:
+* `#[unix_sigpipe = "inherit"]`
+* `#[unix_sigpipe = "sig_dfl"]`
+* `#[unix_sigpipe = "sig_ign"]`
+
+## `#[unix_sigpipe = "inherit"]`
+
+Leave `SIGPIPE` untouched before entering `fn main()`. Unless the parent process has changed the default `SIGPIPE` handler from `SIG_DFL` to something else, this will behave the same as `#[unix_sigpipe = "sig_dfl"]`.
+
+## `#[unix_sigpipe = "sig_dfl"]`
+
+Set the `SIGPIPE` handler to `SIG_DFL`. This will result in your program getting killed if it tries to write to a closed pipe. This is normally what you want if your program produces textual output.
+
+### Example
+
+```rust,no_run
+#![feature(unix_sigpipe)]
+#[unix_sigpipe = "sig_dfl"]
+fn main() { loop { println!("hello world"); } }
+```
+
+```bash
+% ./main | head -n 1
+hello world
+```
+
+## `#[unix_sigpipe = "sig_ign"]`
+
+Set the `SIGPIPE` handler to `SIG_IGN` before invoking `fn main()`. This will result in `ErrorKind::BrokenPipe` errors if you program tries to write to a closed pipe. This is normally what you want if you for example write socket servers, socket clients, or pipe peers.
+
+This is what libstd has done by default since 2014. Omitting `#[unix_sigpipe = "..."]` is the same as having `#[unix_sigpipe = "sig_ign"]`.
+
+### Example
+
+```rust,no_run
+#![feature(unix_sigpipe)]
+#[unix_sigpipe = "sig_ign"]
+fn main() { loop { println!("hello world"); } }
+```
+
+```bash
+% ./main | head -n 1
+hello world
+thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', library/std/src/io/stdio.rs:1016:9
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+```
pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
let kind = match variant.ctor_kind {
- CtorKind::Const => Variant::CLike,
+ CtorKind::Const => Variant::CLike(match variant.discr {
+ ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
+ ty::VariantDiscr::Relative(_) => None,
+ }),
CtorKind::Fn => Variant::Tuple(
variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
),
fn clean_variant_data<'tcx>(
variant: &hir::VariantData<'tcx>,
+ disr_expr: &Option<hir::AnonConst>,
cx: &mut DocContext<'tcx>,
) -> Variant {
match variant {
hir::VariantData::Tuple(..) => {
Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
}
- hir::VariantData::Unit(..) => Variant::CLike,
+ hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| Discriminant {
+ expr: Some(disr.body),
+ value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
+ })),
}
}
}
fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
- let kind = VariantItem(clean_variant_data(&variant.data, cx));
+ let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx));
let what_rustc_thinks =
Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx);
// don't show `pub` for variants, which are always public
#[derive(Clone, Debug)]
pub(crate) enum Variant {
- CLike,
+ CLike(Option<Discriminant>),
Tuple(Vec<Item>),
Struct(VariantStruct),
}
pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
match *self {
Self::Struct(ref struct_) => Some(struct_.has_stripped_entries()),
- Self::CLike | Self::Tuple(_) => None,
+ Self::CLike(..) | Self::Tuple(_) => None,
}
}
}
+#[derive(Clone, Debug)]
+pub(crate) struct Discriminant {
+ // In the case of cross crate re-exports, we don't have the nessesary information
+ // to reconstruct the expression of the discriminant, only the value.
+ pub(super) expr: Option<BodyId>,
+ pub(super) value: DefId,
+}
+
+impl Discriminant {
+ /// Will be `None` in the case of cross-crate reexports, and may be
+ /// simplified
+ pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
+ self.expr.map(|body| print_const_expr(tcx, body))
+ }
+ /// Will always be a machine readable number, without underscores or suffixes.
+ pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> String {
+ print_evaluated_const(tcx, self.value, false).unwrap()
+ }
+}
+
/// Small wrapper around [`rustc_span::Span`] that adds helper methods
/// and enforces calling [`rustc_span::Span::source_callsite()`].
#[derive(Copy, Clone, Debug)]
match *self {
ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
- print_evaluated_const(tcx, def_id)
+ print_evaluated_const(tcx, def_id, true)
}
}
}
}
}
-pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<String> {
+pub(crate) fn print_evaluated_const(
+ tcx: TyCtxt<'_>,
+ def_id: DefId,
+ underscores_and_type: bool,
+) -> Option<String> {
tcx.const_eval_poly(def_id).ok().and_then(|val| {
let ty = tcx.type_of(def_id);
match (val, ty.kind()) {
(ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
(ConstValue::Scalar(_), _) => {
let const_ = mir::ConstantKind::from_value(val, ty);
- Some(print_const_with_custom_print_scalar(tcx, const_))
+ Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type))
}
_ => None,
}
.collect()
}
-fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: mir::ConstantKind<'_>) -> String {
+fn print_const_with_custom_print_scalar(
+ tcx: TyCtxt<'_>,
+ ct: mir::ConstantKind<'_>,
+ underscores_and_type: bool,
+) -> String {
// Use a slightly different format for integer types which always shows the actual value.
// For all other types, fallback to the original `pretty_print_const`.
match (ct, ct.ty().kind()) {
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Uint(ui)) => {
- format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
+ if underscores_and_type {
+ format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
+ } else {
+ int.to_string()
+ }
}
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Int(i)) => {
let ty = tcx.lift(ct.ty()).unwrap();
let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
let data = int.assert_bits(size);
let sign_extended_data = size.sign_extend(data) as i128;
- format!(
- "{}{}",
- format_integer_with_underscore_sep(&sign_extended_data.to_string()),
- i.name_str()
- )
+ if underscores_and_type {
+ format!(
+ "{}{}",
+ format_integer_with_underscore_sep(&sign_extended_data.to_string()),
+ i.name_str()
+ )
+ } else {
+ sign_extended_data.to_string()
+ }
}
_ => ct.to_string(),
}
let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
VariantItem(Variant::Tuple(fields))
}
- Variant::CLike => VariantItem(Variant::CLike),
+ Variant::CLike(disr) => VariantItem(Variant::CLike(disr)),
},
ExternCrateItem { src: _ }
| ImportItem(_)
let where_preds = comma_sep(where_predicates, false);
let clause = if f.alternate() {
if ending == Ending::Newline {
- // add a space so stripping <br> tags and breaking spaces still renders properly
- format!(" where{where_preds}, ")
+ format!(" where{where_preds},")
} else {
format!(" where{where_preds}")
}
if ending == Ending::Newline {
let mut clause = " ".repeat(indent.saturating_sub(1));
- // add a space so stripping <br> tags and breaking spaces still renders properly
- write!(
- clause,
- " <span class=\"where fmt-newline\">where{where_preds}, </span>"
- )?;
+ write!(clause, "<span class=\"where fmt-newline\">where{where_preds},</span>")?;
clause
} else {
// insert a <br> tag after a single space but before multiple spaces at the start
if indent == 0 {
- format!(" <br><span class=\"where\">where{where_preds}</span>")
+ format!("<br><span class=\"where\">where{where_preds}</span>")
} else {
let mut clause = br_with_padding;
clause.truncate(clause.len() - 5 * " ".len());
- write!(clause, " <span class=\"where\">where{where_preds}</span>")?;
+ write!(clause, "<span class=\"where\">where{where_preds}</span>")?;
clause
}
}
// in documentation pages for trait with automatic implementations like "Send" and "Sync".
aliases: &[String],
) {
- let id =
- cx.derive_id(get_id_for_impl(&i.inner_impl().for_, i.inner_impl().trait_.as_ref(), cx));
+ let inner_impl = i.inner_impl();
+ let id = cx.derive_id(get_id_for_impl(&inner_impl.for_, inner_impl.trait_.as_ref(), cx));
let aliases = if aliases.is_empty() {
String::new()
} else {
write!(w, "<h3 class=\"code-header in-band\">");
if let Some(use_absolute) = use_absolute {
- write!(w, "{}", i.inner_impl().print(use_absolute, cx));
+ write!(w, "{}", inner_impl.print(use_absolute, cx));
if show_def_docs {
- for it in &i.inner_impl().items {
+ for it in &inner_impl.items {
if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
w.write_str("<span class=\"where fmt-newline\"> ");
assoc_type(
}
}
} else {
- write!(w, "{}", i.inner_impl().print(false, cx));
+ write!(w, "{}", inner_impl.print(false, cx));
}
write!(w, "</h3>");
- let is_trait = i.inner_impl().trait_.is_some();
+ let is_trait = inner_impl.trait_.is_some();
if is_trait {
if let Some(portability) = portability(&i.impl_item, Some(parent)) {
write!(w, "<span class=\"item-info\">{}</span>", portability);
let Some(v) = shared.cache.impls.get(&def_id) else { return (Vec::new(), Vec::new(), Vec::new()) };
// Since there is no "direct implementation" on the reference primitive type, we filter out
// every implementation which isn't a trait implementation.
- let traits: Vec<_> = v.iter().filter(|i| i.inner_impl().trait_.is_some()).collect();
+ let traits = v.iter().filter(|i| i.inner_impl().trait_.is_some());
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
- traits.into_iter().partition(|t| t.inner_impl().kind.is_auto());
+ traits.partition(|t| t.inner_impl().kind.is_auto());
let (blanket_impl, concrete): (Vec<&Impl>, _) =
concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
let name = v.name.unwrap();
match *v.kind {
clean::VariantItem(ref var) => match var {
- clean::Variant::CLike => write!(w, "{}", name),
+ // FIXME(#101337): Show discriminant
+ clean::Variant::CLike(..) => write!(w, "{}", name),
clean::Variant::Tuple(ref s) => {
write!(w, "{}(", name);
print_tuple_struct_fields(w, cx, s);
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
if let ExprKind::MethodCall(segment, ..) = expr.kind {
- if let Some(hir_id) = segment.hir_id {
- let hir = self.tcx.hir();
- let body_id = hir.enclosing_body_owner(hir_id);
- // FIXME: this is showing error messages for parts of the code that are not
- // compiled (because of cfg)!
- //
- // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
- let typeck_results = self.tcx.typeck_body(
- hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
+ let hir = self.tcx.hir();
+ let body_id = hir.enclosing_body_owner(segment.hir_id);
+ // FIXME: this is showing error messages for parts of the code that are not
+ // compiled (because of cfg)!
+ //
+ // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
+ let typeck_results = 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(
+ segment.ident.span,
+ match hir.span_if_local(def_id) {
+ Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
+ None => LinkFromSrc::External(def_id),
+ },
);
- if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
- self.matches.insert(
- segment.ident.span,
- match hir.span_if_local(def_id) {
- Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
- None => LinkFromSrc::External(def_id),
- },
- );
- }
}
} else if self.handle_macro(expr.span) {
// We don't want to go deeper into the macro.
if line.starts_with(&prefix) {
continue;
}
- if line.ends_with(",") {
+ if line.ends_with(',') {
ret.push(line[..line.len() - 1].to_string());
} else {
// No comma (it's the case for the last added crate line)
a.source,
.search-input,
.search-results .result-name,
-.content table td:first-child > a,
.item-left > a,
.out-of-band,
span.since,
div.impl-items > div:not(.docblock):not(.item-info),
.content ul.crate a.crate,
a.srclink,
-#main-content > .since,
#help-button > button,
details.rustdoc-toggle.top-doc > summary,
details.rustdoc-toggle.top-doc > summary::before,
margin-bottom: 15px;
}
-.content .docblock > .impl-items {
- margin-left: 20px;
- margin-top: -34px;
-}
-.content .docblock >.impl-items table td {
- padding: 0;
-}
-
.item-info {
display: block;
}
margin-bottom: .6em;
}
-.content .impl-items > .item-info {
- margin-left: 40px;
-}
-
-.methods > .item-info, .content .impl-items > .item-info {
- margin-top: -8px;
-}
-
-.impl-items {
- flex-basis: 100%;
-}
-
#main-content > .item-info {
margin-top: 0;
margin-left: 0;
width: 100%;
background-color: var(--button-background-color);
}
+.search-input:focus {
+ border-color: var(--search-input-focused-border-color);
+}
.search-results {
display: none;
float: right;
}
+.rightside:not(a),
+.out-of-band {
+ color: var(--right-side-color);
+}
+
+
.impl-items .srclink, .impl .srclink, .methods .srclink {
/* Override header settings otherwise it's too bold */
font-weight: normal;
.code-attribute {
font-weight: 300;
+ color: var(--code-attribute-color);
}
.item-spacer {
margin-left: 24px;
}
-.toggle-label {
- display: inline-block;
- margin-left: 4px;
- margin-top: 3px;
-}
-
:target > code, :target > .code-header {
opacity: 1;
}
background-color: var(--button-background-color);
}
+#copy-path {
+ color: var(--copy-path-button-color);
+}
+#copy-path > img {
+ filter: var(--copy-path-img-filter);
+}
+#copy-path:hover > img {
+ filter: var(--copy-path-img-hover-filter);
+}
+
@keyframes rotating {
from {
transform: rotate(0deg);
opacity: .5;
}
+details.rustdoc-toggle > summary.hideme > span,
+details.rustdoc-toggle > summary::before,
+.more-examples-toggle summary, .more-examples-toggle .hide-more {
+ color: var(--toggles-color);
+}
+
/* Screen readers see the text version at the end the line.
Visual readers see the icon at the start of the line, but small and transparent. */
details.rustdoc-toggle > summary::after {
background-color: var(--sidebar-background-color);
}
- .source nav:not(.sidebar).sub {
- margin-left: 32px;
- }
-
.content {
margin-left: 0px;
}
#main-content > div > details.rustdoc-toggle > summary::before {
left: -11px;
}
+
+ /* Align summary-nested and unnested item-info gizmos. */
+ .content .impl-items > .item-info {
+ margin-left: 34px;
+ }
}
@media print {
--headings-border-bottom-color: #5c6773;
--border-color: #5c6773;
--button-background-color: #141920;
+ --right-side-color: grey;
+ --code-attribute-color: #999;
+ --toggles-color: #999;
+ --search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */
+ --copy-path-button-color: #fff;
+ --copy-path-img-filter: invert(70%);
+ --copy-path-img-hover-filter: invert(100%);
}
.slider {
background: #333;
}
-details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
- color: #999;
-}
-
details.rustdoc-toggle > summary::before {
filter: invert(100%);
}
background: none;
}
-.rightside:not(a),
-.out-of-band {
- color: grey;
-}
-
.result-name .primitive > i, .result-name .keyword > i {
color: #788797;
}
color: #c5c5c5;
}
-.toggle-label,
-.code-attribute {
- color: #999;
-}
-
:target {
background: rgba(255, 236, 164, 0.06);
border-right: 3px solid rgba(255, 180, 76, 0.85);
/* FIXME: these rules should be at the bottom of the file but currently must be
above the `@media (max-width: 700px)` rules due to a bug in the css checker */
/* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */
-.search-input:focus {}
.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,
.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro {}
.content span.struct,.content a.struct,.block a.current.struct {}
filter: invert(100);
}
-#copy-path {
- color: #fff;
-}
-#copy-path > img {
- filter: invert(70%);
-}
-#copy-path:hover > img {
- filter: invert(100%);
-}
-
#settings-menu > a:hover, #settings-menu > a:focus,
#help-button > button:hover, #help-button > button:focus {
border-color: #e0e0e0;
border-color: white;
color: white;
}
-.more-examples-toggle summary, .more-examples-toggle .hide-more {
- color: #999;
-}
.scraped-example .example-wrap .rust span.highlight {
background: rgb(91, 59, 1);
}
--headings-border-bottom-color: #d2d2d2;
--border-color: #e0e0e0;
--button-background-color: #f0f0f0;
+ --right-side-color: grey;
+ --code-attribute-color: #999;
+ --toggles-color: #999;
+ --search-input-focused-border-color: #008dfd;
+ --copy-path-button-color: #999;
+ --copy-path-img-filter: invert(50%);
+ --copy-path-img-hover-filter: invert(65%);
}
.slider {
background: #333;
}
-details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
- color: #999;
-}
-
details.rustdoc-toggle > summary::before {
filter: invert(100%);
}
.search-input {
color: #111;
- border-color: #f0f0f0;
}
#crate-search-div::after {
filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);
}
-.search-input:focus {
- border-color: #008dfd;
-}
-
.stab { background: #314559; }
.stab.portability > code {
background: none;
}
-.rightside:not(a),
-.out-of-band {
- color: grey;
-}
-
.line-numbers :target { background-color: transparent; }
/* Code highlighting */
background-color: #4e8bca;
}
-.toggle-label,
-.code-attribute {
- color: #999;
-}
-
:target {
background-color: #494a3d;
border-right: 3px solid #bb7410;
border-color: #ffb900;
}
-#copy-path {
- color: #999;
-}
-#copy-path > img {
- filter: invert(50%);
-}
-#copy-path:hover > img {
- filter: invert(65%);
-}
-
.search-results .result-name span.alias {
color: #fff;
}
border-color: white;
color: white;
}
-.more-examples-toggle summary, .more-examples-toggle .hide-more {
- color: #999;
-}
.scraped-example .example-wrap .rust span.highlight {
background: rgb(91, 59, 1);
}
--headings-border-bottom-color: #ddd;
--border-color: #e0e0e0;
--button-background-color: #fff;
+ --right-side-color: grey;
+ --code-attribute-color: #999;
+ --toggles-color: #999;
+ --search-input-focused-border-color: #66afe9;
+ --copy-path-button-color: #999;
+ --copy-path-img-filter: invert(50%);
+ --copy-path-img-hover-filter: invert(35%);
}
.slider {
background: #eee;
}
-details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
- color: #999;
-}
-
#crate-search-div::after {
/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);
filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);
}
-.search-input:focus {
- border-color: #66afe9;
-}
-
.stab { background: #FFF5D6; border-color: #FFC600; }
.stab.portability > code { background: none; }
-.rightside:not(a),
-.out-of-band {
- color: grey;
-}
-
.line-numbers :target { background-color: transparent; }
/* Code highlighting */
background-color: #4e8bca;
}
-.toggle-label,
-.code-attribute {
- color: #999;
-}
-
:target {
background: #FDFFD3;
border-right: 3px solid #AD7C37;
border-color: #717171;
}
-#copy-path {
- color: #999;
-}
-#copy-path > img {
- filter: invert(50%);
-}
-#copy-path:hover > img {
- filter: invert(35%);
-}
-
.search-results .result-name span.alias {
color: #000;
}
border-color: black;
color: black;
}
-.more-examples-toggle summary, .more-examples-toggle .hide-more {
- color: #999;
-}
.scraped-example .example-wrap .rust span.highlight {
background: #fcffd6;
}
},
QPath(box clean::QPathData { assoc, self_type, trait_, .. }) => Type::QualifiedPath {
name: assoc.name.to_string(),
- args: Box::new(assoc.args.clone().into_tcx(tcx)),
+ args: Box::new(assoc.args.into_tcx(tcx)),
self_type: Box::new(self_type.into_tcx(tcx)),
trait_: trait_.into_tcx(tcx),
},
fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
use clean::Variant::*;
match variant {
- CLike => Variant::Plain,
+ CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))),
Tuple(fields) => Variant::Tuple(
fields
.into_iter()
}
}
+impl FromWithTcx<clean::Discriminant> for Discriminant {
+ fn from_tcx(disr: clean::Discriminant, tcx: TyCtxt<'_>) -> Self {
+ Discriminant {
+ // expr is only none if going throught the inlineing path, which gets
+ // `rustc_middle` types, not `rustc_hir`, but because JSON never inlines
+ // the expr is always some.
+ expr: disr.expr(tcx).unwrap(),
+ value: disr.value(tcx),
+ }
+ }
+}
+
impl FromWithTcx<clean::Import> for Import {
fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
use clean::ImportKind::*;
///
/// This is just a wrapper around [`TyCtxt::impl_item_implementor_ids()`] and
/// [`TyCtxt::associated_item()`] (with some helpful logging added).
-#[instrument(level = "debug", skip(tcx))]
+#[instrument(level = "debug", skip(tcx), ret)]
fn trait_assoc_to_impl_assoc_item<'tcx>(
tcx: TyCtxt<'tcx>,
impl_id: DefId,
debug!(?trait_to_impl_assoc_map);
let impl_assoc_id = *trait_to_impl_assoc_map.get(&trait_assoc_id)?;
debug!(?impl_assoc_id);
- let impl_assoc = tcx.associated_item(impl_assoc_id);
- debug!(?impl_assoc);
- Some(impl_assoc)
+ Some(tcx.associated_item(impl_assoc_id))
}
/// Given a type, return all trait impls in scope in `module` for that type.
use crate::clean::cfg::Cfg;
use crate::clean::inline::{load_attrs, merge_attrs};
-use crate::clean::{Crate, Item};
+use crate::clean::{Crate, Item, ItemKind};
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::passes::Pass;
cx: &'a mut DocContext<'tcx>,
}
-impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> {
- fn fold_item(&mut self, mut item: Item) -> Option<Item> {
- let old_parent_cfg = self.parent_cfg.clone();
+impl<'a, 'tcx> CfgPropagator<'a, 'tcx> {
+ // Some items need to merge their attributes with their parents' otherwise a few of them
+ // (mostly `cfg` ones) will be missing.
+ fn merge_with_parent_attributes(&mut self, item: &mut Item) {
+ let check_parent = match &*item.kind {
+ // impl blocks can be in different modules with different cfg and we need to get them
+ // as well.
+ ItemKind::ImplItem(_) => false,
+ kind if kind.is_non_assoc() => true,
+ _ => return,
+ };
- if item.kind.is_non_assoc() &&
- let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
- let hir = self.cx.tcx.hir();
- let hir_id = hir.local_def_id_to_hir_id(def_id);
+ let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local())
+ else { return };
+
+ let hir = self.cx.tcx.hir();
+ let hir_id = hir.local_def_id_to_hir_id(def_id);
+
+ if check_parent {
let expected_parent = hir.get_parent_item(hir_id);
+ // If parents are different, it means that `item` is a reexport and we need
+ // to compute the actual `cfg` by iterating through its "real" parents.
+ if self.parent == Some(expected_parent) {
+ return;
+ }
+ }
- // If parents are different, it means that `item` is a reexport and we need to compute
- // the actual `cfg` by iterating through its "real" parents.
- if self.parent != Some(expected_parent) {
- let mut attrs = Vec::new();
- for (parent_hir_id, _) in hir.parent_iter(hir_id) {
- if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) {
- attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id()));
- }
- }
- let (_, cfg) =
- merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
- item.cfg = cfg;
+ let mut attrs = Vec::new();
+ for (parent_hir_id, _) in hir.parent_iter(hir_id) {
+ if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) {
+ attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id()));
}
}
+ let (_, cfg) = merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
+ item.cfg = cfg;
+ }
+}
+
+impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> {
+ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
+ let old_parent_cfg = self.parent_cfg.clone();
+
+ self.merge_with_parent_attributes(&mut item);
+
let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) {
(None, None) => None,
(Some(rc), None) | (None, Some(rc)) => Some(rc),
clean::ExternCrateItem { .. } => {}
clean::ImportItem(ref imp) => {
// Because json doesn't inline imports from private modules, we need to mark
- // the imported item as retained so it's impls won't be stripped.i
+ // the imported item as retained so it's impls won't be stripped.
//
// FIXME: Is it necessary to check for json output here: See
// https://github.com/rust-lang/rust/pull/100325#discussion_r941495215
return;
}
}
- hir::ExprKind::MethodCall(path, _, call_span) => {
+ hir::ExprKind::MethodCall(path, _, _, call_span) => {
let types = tcx.typeck(ex.hir_id.owner);
let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else {
trace!("type_dependent_def_id({}) = None", ex.hir_id);
VariantItem(i) => match i {
Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
- Variant::CLike => {}
+ Variant::CLike(_) => {}
},
ExternCrateItem { src: _ }
| ImportItem(_)
-Subproject commit e3be3f64ecac101d14ceda759ba078ad0aaf3747
+Subproject commit 670e5f673acb736acbfce65e0ffe2c8cd115b93f
use serde::{Deserialize, Serialize};
/// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 18;
+pub const FORMAT_VERSION: u32 = 19;
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
/// about the language items in the local crate, as well as info about external items to allow
#[serde(rename_all = "snake_case")]
#[serde(tag = "variant_kind", content = "variant_inner")]
pub enum Variant {
- Plain,
+ Plain(Option<Discriminant>),
Tuple(Vec<Type>),
Struct(Vec<Id>),
}
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Discriminant {
+ /// The expression that produced the discriminant.
+ ///
+ /// Unlike `value`, this preserves the original formatting (eg suffixes,
+ /// hexadecimal, and underscores), making it unsuitable to be machine
+ /// interpreted.
+ ///
+ /// In some cases, when the value is to complex, this may be `"{ _ }"`.
+ /// When this occurs is unstable, and may change without notice.
+ pub expr: String,
+ /// The numerical value of the discriminant. Stored as a string due to
+ /// JSON's poor support for large integers, and the fact that it would need
+ /// to store from [`i128::MIN`] to [`u128::MAX`].
+ pub value: String,
+}
+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum StructType {
use std::convert::TryFrom;
<[T; N.get()]>::try_from(())
//~^ error: the trait bound
+ //~| error: the trait bound
//~| error: mismatched types
}
-// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
+
+// FIXME: This test was broken by the derefer change.
// example from #68867
type CSSFloat = f32;
}
// EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
-// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyConstCondition-final.after
#[no_mangle]
pub extern "C" fn try_sum(
x: &ViewportPercentageLength,
+++ /dev/null
-- // MIR for `try_sum` before EarlyOtherwiseBranch
-+ // MIR for `try_sum` after SimplifyConstCondition-final
-
- fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> Result<ViewportPercentageLength, ()> {
- debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+1:5: +1:6
- debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+2:5: +2:10
- let mut _0: std::result::Result<ViewportPercentageLength, ()>; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:+3:6: +3:42
- let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6
- let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16
- let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23
- let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:21: +6:30
- let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:21: +7:30
- let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:23: +8:34
- let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:23: +9:34
- let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:11: +6:18
- let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
- let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
- let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49
- let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41
- let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49
- let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
- let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
- let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49
- let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41
- let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49
- let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
- let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
- let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55
- let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47
- let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55
- let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
- let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
- let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55
- let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47
- let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55
- let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:14: +10:28
- let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
- let mut _34: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _35: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _36: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _37: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _38: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _39: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _40: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _41: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _42: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _43: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _44: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _45: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- let mut _46: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- scope 1 {
-- debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
-- debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
-+ debug one => _15; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
-+ debug other => _16; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
- }
- scope 2 {
-- debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
-- debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
-+ debug one => _20; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
-+ debug other => _21; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
- }
- scope 3 {
-- debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
-- debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
-+ debug one => _25; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
-+ debug other => _26; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
- }
- scope 4 {
-- debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
-- debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
-+ debug one => _30; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
-+ debug other => _31; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
- }
-
- bb0: {
-- StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6
-- StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-- StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16
-- _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16
-+ (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16
- StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23
- _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23
- Deinit(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-- (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24
-- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24
- _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
- }
-
- bb1: {
- _35 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
- }
-
- bb2: {
- StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
- nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
- Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
- nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
- discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
- StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:27: +10:28
-- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
-- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
- return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
- }
-
- bb3: {
- _36 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
- }
-
- bb4: {
- _37 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
- }
-
- bb5: {
- _38 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
- }
-
- bb6: {
-- StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
- _39 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
-- _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
-- StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
-+ _15 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
- _40 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
-- _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
-- StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49
-- StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41
-- _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41
-- StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49
-- _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49
-- _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49
-- StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49
-- StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49
-- Deinit(_3); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
-- ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
-- discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
-- StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
-- StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
-- StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
-+ _16 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49
-+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
-+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
- }
-
- bb7: {
-- StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
- _41 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
-- _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
-- StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
-+ _20 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
- _42 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
-- _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
-- StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49
-- StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41
-- _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41
-- StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49
-- _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49
-- _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49
-- StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49
-- StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49
-- Deinit(_3); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
-- ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
-- discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
-- StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
-- StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
-- StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
-+ _21 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49
-+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
-+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
- }
-
- bb8: {
-- StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
- _43 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
-- _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
-- StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
-+ _25 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
- _44 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
-- _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
-- StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55
-- StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47
-- _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47
-- StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55
-- _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55
-- _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55
-- StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55
-- StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55
-- Deinit(_3); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
-- ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
-- discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
-- StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
-- StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
-- StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
-+ _26 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55
-+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
-+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
- }
-
- bb9: {
-- StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
- _45 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
-- _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
-- StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
-+ _30 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
- _46 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
-- _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
-- StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55
-- StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47
-- _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47
-- StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55
-- _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55
-- _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55
-- StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55
-- StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55
-- Deinit(_3); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
-- ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
-- discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
-- StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
-- StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
-- StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
-+ _31 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55
-+ ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55
-+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
-+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
-+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
- }
-
- bb10: {
- Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
-- ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
- discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
-- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
-- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
-+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
- return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
- }
-
- bb11: {
- unreachable; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
- }
- }
-
StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24
_34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
_11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
+ switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
}
bb1: {
bb2: {
StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
- nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
+ Deinit(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
- nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
+ ((_0 as Err).0: ()) = move _33; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:27: +10:28
StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
- return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
+ goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
}
bb3: {
discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
- return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
+ goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
}
bb11: {
- unreachable; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
+ return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
}
}
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR issue_73223.main.SimplifyArmIdentity.diff
-// EMIT_MIR issue_73223.main.PreCodegen.diff
+++ /dev/null
-- // MIR for `main` before PreCodegen
-+ // MIR for `main` after PreCodegen
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11
- let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
- let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- let _3: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _7: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _11: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _12: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _14: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _16: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _17: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _19: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 1 {
- debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14
- let _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
- scope 3 {
- debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
- let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _9: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _20: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 4 {
- debug left_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug right_val => _9; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _13: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 5 {
- debug kind => _13; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
- }
- }
- }
- scope 2 {
- debug v => _3; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
- StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- _1 = _3; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
- StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21
- StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
- StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
- StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _6 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _20 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
- _7 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_5.1: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _8 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _9 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _12 = (*_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _11 = Eq(move _12, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _10 = Not(move _11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- switchInt(move _10) -> [false: bb2, otherwise: bb1]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb1: {
- StorageLive(_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_14); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_15); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_16); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _16 = _8; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _15 = _16; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_17); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _18 = _9; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _17 = _18; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- discriminant(_19) = 0; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _14 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
- }
-
- bb2: {
- StorageDead(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2
- StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
- return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
- }
- }
-
+++ /dev/null
-- // MIR for `main` before PreCodegen
-+ // MIR for `main` after PreCodegen
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11
- let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
- let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- let _3: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _7: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _11: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _12: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _14: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _16: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _17: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _19: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 1 {
- debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14
- let _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
- scope 3 {
- debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
- let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _9: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _20: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 4 {
- debug left_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug right_val => _9; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _13: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 5 {
- debug kind => _13; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
- }
- }
- }
- scope 2 {
- debug v => _3; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
- StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- _1 = _3; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
- StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21
- StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
- StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
- StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _6 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _20 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
- _7 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_5.1: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _8 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _9 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _12 = (*_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _11 = Eq(move _12, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _10 = Not(move _11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- switchInt(move _10) -> [false: bb2, otherwise: bb1]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb1: {
- StorageLive(_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_14); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_15); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_16); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _16 = _8; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _15 = _16; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_17); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _18 = _9; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _17 = _18; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- discriminant(_19) = 0; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _14 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
- }
-
- bb2: {
- StorageDead(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2
- StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
- return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
- }
- }
-
+++ /dev/null
-- // MIR for `array_bound` before InstCombine
-+ // MIR for `array_bound` after InstCombine
-
- fn array_bound(_1: usize, _2: &[u8; N]) -> u8 {
- debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:36: +0:41
- debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:50: +0:55
- let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:70: +0:72
- let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-
- bb0: {
- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ _7 = _2; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- _11 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21
-- _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- }
-
- bb1: {
- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- }
-
- bb2: {
- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
- goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6
- }
-
- bb3: {
- _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:11
- goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6
- }
-
- bb4: {
- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+5:5: +5:6
- return; // scope 0 at $DIR/lower_array_len.rs:+6:2: +6:2
- }
- }
-
+++ /dev/null
-- // MIR for `array_bound` before SimplifyLocals
-+ // MIR for `array_bound` after SimplifyLocals
-
- fn array_bound(_1: usize, _2: &[u8; N]) -> u8 {
- debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:36: +0:41
- debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:50: +0:55
- let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:70: +0:72
- let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-- let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-
- bb0: {
- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21
- _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- }
-
- bb1: {
-- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- }
-
- bb2: {
-- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
-+ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
- goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6
- }
-
- bb3: {
- _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:11
- goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6
- }
-
- bb4: {
- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+5:5: +5:6
- return; // scope 0 at $DIR/lower_array_len.rs:+6:2: +6:2
- }
- }
-
+++ /dev/null
-- // MIR for `array_bound_mut` before InstCombine
-+ // MIR for `array_bound_mut` after InstCombine
-
- fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
- debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:40: +0:45
- debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:54: +0:59
- let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:78: +0:80
- let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
- let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
- let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
- let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-
- bb0: {
- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- _14 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21
-- _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- }
-
- bb1: {
- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- }
-
- bb2: {
- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
- goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6
- }
-
- bb3: {
- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
- _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-- _12 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-+ _12 = const N; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
- _13 = Lt(_11, _12); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
- }
-
- bb4: {
- (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22
- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23
- _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+6:9: +6:11
- goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6
- }
-
- bb5: {
- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+7:5: +7:6
- return; // scope 0 at $DIR/lower_array_len.rs:+8:2: +8:2
- }
- }
-
+++ /dev/null
-- // MIR for `array_bound_mut` before SimplifyLocals
-+ // MIR for `array_bound_mut` after SimplifyLocals
-
- fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
- debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:40: +0:45
- debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:54: +0:59
- let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:78: +0:80
- let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-- let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-- let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-- let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-- let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ let _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-+ let mut _10: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-+ let mut _11: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-
- bb0: {
- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
- StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21
- _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
- switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
- }
-
- bb1: {
-- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
- }
-
- bb2: {
-- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
-+ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
- goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6
- }
-
- bb3: {
-- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-- _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-- _12 = const N; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-- _13 = Lt(const 0_usize, _12); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-+ StorageLive(_9); // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-+ _9 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-+ _10 = const N; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-+ _11 = Lt(const 0_usize, _10); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-+ assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
- }
-
- bb4: {
-- (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22
-- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23
-+ (*_2)[_9] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22
-+ StorageDead(_9); // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23
- _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+6:9: +6:11
- goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6
- }
-
- bb5: {
- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+7:5: +7:6
- return; // scope 0 at $DIR/lower_array_len.rs:+8:2: +8:2
- }
- }
-
+++ /dev/null
-- // MIR for `array_len` before InstCombine
-+ // MIR for `array_len` after InstCombine
-
- fn array_len(_1: &[u8; N]) -> usize {
- debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:34: +0:37
- let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57
- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ _3 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8
-- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14
- return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2
- }
- }
-
+++ /dev/null
-- // MIR for `array_len` before SimplifyLocals
-+ // MIR for `array_len` after SimplifyLocals
-
- fn array_len(_1: &[u8; N]) -> usize {
- debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:34: +0:37
- let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57
-- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-
- bb0: {
-- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8
- _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14
- return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2
- }
- }
-
+++ /dev/null
-- // MIR for `array_len_by_value` before InstCombine
-+ // MIR for `array_len_by_value` after InstCombine
-
- fn array_len_by_value(_1: [u8; N]) -> usize {
- debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:46
- let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65
- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8
-- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14
- return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2
- }
- }
-
+++ /dev/null
-- // MIR for `array_len_by_value` before SimplifyLocals
-+ // MIR for `array_len_by_value` after SimplifyLocals
-
- fn array_len_by_value(_1: [u8; N]) -> usize {
- debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:46
- let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65
-- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-
- bb0: {
-- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8
- _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14
- return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2
- }
- }
-
-// compile-flags: -Z mir-opt-level=4
+// unit-test: NormalizeArrayLen
+// compile-flags: -Zmir-enable-passes=+LowerSliceLenCalls
// EMIT_MIR lower_array_len.array_bound.NormalizeArrayLen.diff
-// EMIT_MIR lower_array_len.array_bound.SimplifyLocals.diff
-// EMIT_MIR lower_array_len.array_bound.InstCombine.diff
pub fn array_bound<const N: usize>(index: usize, slice: &[u8; N]) -> u8 {
if index < slice.len() {
slice[index]
}
// EMIT_MIR lower_array_len.array_bound_mut.NormalizeArrayLen.diff
-// EMIT_MIR lower_array_len.array_bound_mut.SimplifyLocals.diff
-// EMIT_MIR lower_array_len.array_bound_mut.InstCombine.diff
pub fn array_bound_mut<const N: usize>(index: usize, slice: &mut [u8; N]) -> u8 {
if index < slice.len() {
slice[index]
}
// EMIT_MIR lower_array_len.array_len.NormalizeArrayLen.diff
-// EMIT_MIR lower_array_len.array_len.SimplifyLocals.diff
-// EMIT_MIR lower_array_len.array_len.InstCombine.diff
pub fn array_len<const N: usize>(arr: &[u8; N]) -> usize {
arr.len()
}
// EMIT_MIR lower_array_len.array_len_by_value.NormalizeArrayLen.diff
-// EMIT_MIR lower_array_len.array_len_by_value.SimplifyLocals.diff
-// EMIT_MIR lower_array_len.array_len_by_value.InstCombine.diff
pub fn array_len_by_value<const N: usize>(arr: [u8; N]) -> usize {
arr.len()
}
--- /dev/null
+// MIR for `array_bound` after PreCodegen
+
+fn array_bound(_1: usize, _2: &[u8; N]) -> u8 {
+ debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:36: +0:41
+ debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:50: +0:55
+ let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:70: +0:72
+ let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+ let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+ let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ let _6: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+ let mut _7: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ let mut _8: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+
+ bb0: {
+ StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+ StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+ _4 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+ StorageLive(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+ StorageDead(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+ StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+ switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+ }
+
+ bb1: {
+ StorageLive(_6); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+ _6 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+ _7 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ }
+
+ bb2: {
+ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ StorageDead(_6); // scope 0 at $DIR/lower_array_len_e2e.rs:+3:5: +3:6
+ goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6
+ }
+
+ bb3: {
+ _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:11
+ goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6
+ }
+
+ bb4: {
+ StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+5:5: +5:6
+ return; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:2: +6:2
+ }
+}
--- /dev/null
+// MIR for `array_bound_mut` after PreCodegen
+
+fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
+ debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:40: +0:45
+ debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:54: +0:59
+ let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:78: +0:80
+ let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+ let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+ let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ let _6: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+ let mut _7: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ let mut _8: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ let _9: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+ let mut _10: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+ let mut _11: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+
+ bb0: {
+ StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+ StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+ _4 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+ StorageLive(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+ StorageDead(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+ StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+ switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+ }
+
+ bb1: {
+ StorageLive(_6); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+ _6 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+ _7 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ }
+
+ bb2: {
+ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ StorageDead(_6); // scope 0 at $DIR/lower_array_len_e2e.rs:+3:5: +3:6
+ goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6
+ }
+
+ bb3: {
+ StorageLive(_9); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+ _9 = const 0_usize; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+ _10 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+ _11 = Lt(const 0_usize, _10); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+ assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+ }
+
+ bb4: {
+ (*_2)[_9] = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22
+ StorageDead(_9); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23
+ _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:9: +6:11
+ goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6
+ }
+
+ bb5: {
+ StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+7:5: +7:6
+ return; // scope 0 at $DIR/lower_array_len_e2e.rs:+8:2: +8:2
+ }
+}
--- /dev/null
+// MIR for `array_len` after PreCodegen
+
+fn array_len(_1: &[u8; N]) -> usize {
+ debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:34: +0:37
+ let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:52: +0:57
+
+ bb0: {
+ _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14
+ return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2
+ }
+}
--- /dev/null
+// MIR for `array_len_by_value` after PreCodegen
+
+fn array_len_by_value(_1: [u8; N]) -> usize {
+ debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:43: +0:46
+ let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:60: +0:65
+
+ bb0: {
+ _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14
+ return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2
+ }
+}
--- /dev/null
+// compile-flags: -Z mir-opt-level=4
+
+// EMIT_MIR lower_array_len_e2e.array_bound.PreCodegen.after.mir
+pub fn array_bound<const N: usize>(index: usize, slice: &[u8; N]) -> u8 {
+ if index < slice.len() {
+ slice[index]
+ } else {
+ 42
+ }
+}
+
+// EMIT_MIR lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir
+pub fn array_bound_mut<const N: usize>(index: usize, slice: &mut [u8; N]) -> u8 {
+ if index < slice.len() {
+ slice[index]
+ } else {
+ slice[0] = 42;
+
+ 42
+ }
+}
+
+// EMIT_MIR lower_array_len_e2e.array_len.PreCodegen.after.mir
+pub fn array_len<const N: usize>(arr: &[u8; N]) -> usize {
+ arr.len()
+}
+
+// EMIT_MIR lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir
+pub fn array_len_by_value<const N: usize>(arr: [u8; N]) -> usize {
+ arr.len()
+}
+
+fn main() {
+ let _ = array_bound(3, &[0, 1, 2, 3]);
+ let mut tmp = [0, 1, 2, 3, 4];
+ let _ = array_bound_mut(3, &mut [0, 1, 2, 3]);
+ let _ = array_len(&[0]);
+ let _ = array_len_by_value([0, 2]);
+}
bb0: {
- _0 = std::intrinsics::min_align_of::<T>() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:19:5: 19:40
+- // + span: $DIR/lower_intrinsics.rs:21:5: 21:40
- // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::<T>}, val: Value(<ZST>) }
+ _0 = AlignOf(T); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42
_3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44
- _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:74:5: 74:41
+- // + span: $DIR/lower_intrinsics.rs:49:5: 49:41
- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) }
+ _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
_19 = const discriminant::<T>::promoted[2]; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
// mir::Constant
- // + span: $DIR/lower_intrinsics.rs:75:42: 75:44
+ // + span: $DIR/lower_intrinsics.rs:50:42: 50:44
// + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) }
_7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
_6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
- _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:75:5: 75:41
+- // + span: $DIR/lower_intrinsics.rs:50:5: 50:41
- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) }
+ _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
+ goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
_18 = const discriminant::<T>::promoted[1]; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
// mir::Constant
- // + span: $DIR/lower_intrinsics.rs:76:42: 76:45
+ // + span: $DIR/lower_intrinsics.rs:51:42: 51:45
// + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) }
_11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
_10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:76:5: 76:41
+- // + span: $DIR/lower_intrinsics.rs:51:5: 51:41
- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) }
+ _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
+ goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
_17 = const discriminant::<T>::promoted[0]; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
// mir::Constant
- // + span: $DIR/lower_intrinsics.rs:77:42: 77:47
+ // + span: $DIR/lower_intrinsics.rs:52:42: 52:47
// + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) }
_15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
_14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
- _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:77:5: 77:41
+- // + span: $DIR/lower_intrinsics.rs:52:5: 52:41
- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) }
+ _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
+ goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
StorageDead(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:48: +4:49
StorageDead(_13); // scope 0 at $DIR/lower_intrinsics.rs:+4:48: +4:49
_0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:+0:30: +5:2
- drop(_1) -> bb5; // scope 0 at $DIR/lower_intrinsics.rs:+5:1: +5:2
+ drop(_1) -> [return: bb5, unwind: bb6]; // scope 0 at $DIR/lower_intrinsics.rs:+5:1: +5:2
}
bb5: {
return; // scope 0 at $DIR/lower_intrinsics.rs:+5:2: +5:2
}
+
+ bb6 (cleanup): {
+ resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +5:2
+ }
}
+++ /dev/null
-// MIR for `f_u64` before PreCodegen
-
-fn f_u64() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:16: +0:16
- let mut _1: u64; // in scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21
- scope 1 (inlined f_dispatch::<u64>) { // at $DIR/lower_intrinsics.rs:40:5: 40:21
- debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:44:22: 44:23
- let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21
- let mut _3: u64; // in scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20
- scope 2 (inlined std::mem::size_of::<u64>) { // at $DIR/lower_intrinsics.rs:45:8: 45:32
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21
- _1 = const 0_u64; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21
- StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21
- StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20
- _3 = move _1; // scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20
- _2 = f_non_zst::<u64>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:48:9: 48:18
- // + literal: Const { ty: fn(u64) {f_non_zst::<u64>}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:48:20: 48:21
- StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:48:21: 48:22
- StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21
- return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
- }
-}
+++ /dev/null
-// MIR for `f_unit` before PreCodegen
-
-fn f_unit() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:17: +0:17
- let mut _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:16: +1:18
- scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics.rs:34:5: 34:19
- debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:44:22: 44:23
- let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
- let mut _3: (); // in scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16
- scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics.rs:45:8: 45:32
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:16: +1:18
- StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
- StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16
- _2 = f_zst::<()>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:46:9: 46:14
- // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:46:16: 46:17
- StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:46:17: 46:18
- StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:18: +1:19
- return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
- }
-}
_2 = move _1; // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31
- _0 = std::intrinsics::forget::<T>(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:24:5: 24:29
+- // + span: $DIR/lower_intrinsics.rs:26:5: 26:29
- // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::<T>}, val: Value(<ZST>) }
+ _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32
StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:18
_1 = std::intrinsics::size_of::<T>; // scope 0 at $DIR/lower_intrinsics.rs:+2:21: +2:51
// mir::Constant
- // + span: $DIR/lower_intrinsics.rs:62:21: 62:51
+ // + span: $DIR/lower_intrinsics.rs:37:21: 37:51
// + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(<ZST>) }
StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14
_2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14
-// compile-flags: -Cpanic=abort
+// unit-test: LowerIntrinsics
+// ignore-wasm32 compiled with panic=abort by default
+
#![feature(core_intrinsics)]
#![crate_type = "lib"]
unsafe { core::intrinsics::unreachable() };
}
-// EMIT_MIR lower_intrinsics.f_unit.PreCodegen.before.mir
-pub fn f_unit() {
- f_dispatch(());
-}
-
-
-// EMIT_MIR lower_intrinsics.f_u64.PreCodegen.before.mir
-pub fn f_u64() {
- f_dispatch(0u64);
-}
-
-#[inline(always)]
-pub fn f_dispatch<T>(t: T) {
- if std::mem::size_of::<T>() == 0 {
- f_zst(t);
- } else {
- f_non_zst(t);
- }
-}
-
-#[inline(never)]
-pub fn f_zst<T>(_t: T) {
-}
-
-#[inline(never)]
-pub fn f_non_zst<T>(_t: T) {}
-
// EMIT_MIR lower_intrinsics.non_const.LowerIntrinsics.diff
pub fn non_const<T>() -> usize {
// Check that lowering works with non-const operand as a func.
bb0: {
- _0 = std::intrinsics::size_of::<T>() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:14:5: 14:35
+- // + span: $DIR/lower_intrinsics.rs:16:5: 16:35
- // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(<ZST>) }
+ _0 = SizeOf(T); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37
StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
- _3 = std::intrinsics::unreachable(); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:29:14: 29:43
+- // + span: $DIR/lower_intrinsics.rs:31:14: 31:43
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(<ZST>) }
+ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
}
_5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:48: +1:49
- _3 = wrapping_add::<i32>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:7:14: 7:44
+- // + span: $DIR/lower_intrinsics.rs:9:14: 9:44
- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_add::<i32>}, val: Value(<ZST>) }
+ _3 = Add(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50
_8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:48: +2:49
- _6 = wrapping_sub::<i32>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:8:14: 8:44
+- // + span: $DIR/lower_intrinsics.rs:10:14: 10:44
- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_sub::<i32>}, val: Value(<ZST>) }
+ _6 = Sub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50
+ goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50
_11 = _2; // scope 2 at $DIR/lower_intrinsics.rs:+3:48: +3:49
- _9 = wrapping_mul::<i32>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:9:14: 9:44
+- // + span: $DIR/lower_intrinsics.rs:11:14: 11:44
- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_mul::<i32>}, val: Value(<ZST>) }
+ _9 = Mul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50
+ goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50
--- /dev/null
+// MIR for `f_u64` after PreCodegen
+
+fn f_u64() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics_e2e.rs:+0:16: +0:16
+ let mut _1: u64; // in scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21
+ scope 1 (inlined f_dispatch::<u64>) { // at $DIR/lower_intrinsics_e2e.rs:15:5: 15:21
+ debug t => _1; // in scope 1 at $DIR/lower_intrinsics_e2e.rs:19:22: 19:23
+ let _2: (); // in scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21
+ let mut _3: u64; // in scope 1 at $DIR/lower_intrinsics_e2e.rs:23:19: 23:20
+ scope 2 (inlined std::mem::size_of::<u64>) { // at $DIR/lower_intrinsics_e2e.rs:20:8: 20:32
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21
+ _1 = const 0_u64; // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21
+ StorageLive(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21
+ StorageLive(_3); // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:19: 23:20
+ _3 = move _1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:19: 23:20
+ _2 = f_non_zst::<u64>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21
+ // mir::Constant
+ // + span: $DIR/lower_intrinsics_e2e.rs:23:9: 23:18
+ // + literal: Const { ty: fn(u64) {f_non_zst::<u64>}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_3); // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:20: 23:21
+ StorageDead(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:21: 23:22
+ StorageDead(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21
+ return; // scope 0 at $DIR/lower_intrinsics_e2e.rs:+2:2: +2:2
+ }
+}
--- /dev/null
+// MIR for `f_unit` after PreCodegen
+
+fn f_unit() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics_e2e.rs:+0:17: +0:17
+ let mut _1: (); // in scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:16: +1:18
+ scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics_e2e.rs:9:5: 9:19
+ debug t => _1; // in scope 1 at $DIR/lower_intrinsics_e2e.rs:19:22: 19:23
+ let _2: (); // in scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
+ let mut _3: (); // in scope 1 at $DIR/lower_intrinsics_e2e.rs:21:15: 21:16
+ scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics_e2e.rs:20:8: 20:32
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:16: +1:18
+ StorageLive(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
+ StorageLive(_3); // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:15: 21:16
+ _2 = f_zst::<()>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
+ // mir::Constant
+ // + span: $DIR/lower_intrinsics_e2e.rs:21:9: 21:14
+ // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_3); // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:16: 21:17
+ StorageDead(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:17: 21:18
+ StorageDead(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:18: +1:19
+ return; // scope 0 at $DIR/lower_intrinsics_e2e.rs:+2:2: +2:2
+ }
+}
--- /dev/null
+// Checks that we do not have any branches in the MIR for the two tested functions.
+
+// compile-flags: -Cpanic=abort
+#![feature(core_intrinsics)]
+#![crate_type = "lib"]
+
+// EMIT_MIR lower_intrinsics_e2e.f_unit.PreCodegen.after.mir
+pub fn f_unit() {
+ f_dispatch(());
+}
+
+
+// EMIT_MIR lower_intrinsics_e2e.f_u64.PreCodegen.after.mir
+pub fn f_u64() {
+ f_dispatch(0u64);
+}
+
+#[inline(always)]
+pub fn f_dispatch<T>(t: T) {
+ if std::mem::size_of::<T>() == 0 {
+ f_zst(t);
+ } else {
+ f_non_zst(t);
+ }
+}
+
+#[inline(never)]
+pub fn f_zst<T>(_t: T) {
+}
+
+#[inline(never)]
+pub fn f_non_zst<T>(_t: T) {}
- _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22
- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22
- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21
-- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
+- Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
- }
-
+ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
_4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22
_5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21
-- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
+ Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
- }
-
- _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22
- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22
- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21
-- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
+- Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
- }
-
+ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
_4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22
_5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21
-- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
+ Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
- }
-
fn foo(_1: Option<()>) -> () {
debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11
let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25
- let mut _2: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
-+ let mut _3: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
++ let mut _4: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
-- switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- }
--
-- bb1: {
+ StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
+- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ _4 = move _3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ StorageDead(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb1: {
+- _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb2: {
+- _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb3: {
-+ StorageLive(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ _3 = move _2; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ StorageDead(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+- }
+-
+- bb4: {
+ Deinit(_0); // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
+ }
+
+- bb5: {
++ bb2: {
+ _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
+ }
+
+- bb6: {
++ bb3: {
+ StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6
return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
}
}
fn foo(_1: Option<()>) -> () {
debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11
let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25
- let mut _2: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
-+ let mut _3: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
++ let mut _4: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
-- switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- }
--
-- bb1: {
+ StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
+- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ _4 = move _3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ StorageDead(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb1: {
+- _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb2: {
+- _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb3: {
-+ StorageLive(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ _3 = move _2; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ StorageDead(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+- }
+-
+- bb4: {
+ Deinit(_0); // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
+ }
+
+- bb5: {
++ bb2: {
+ _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
+ }
+
+- bb6: {
++ bb3: {
+ StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6
return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
}
}
+++ /dev/null
-// MIR for `foo` before PreCodegen
-
-fn foo(_1: Option<()>) -> () {
- debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11
- let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25
-
- bb0: {
- return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
- }
-}
+++ /dev/null
-// MIR for `foo` before PreCodegen
-
-fn foo(_1: Option<()>) -> () {
- debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11
- let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25
-
- bb0: {
- return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
- }
-}
fn match_nested_if() -> bool {
let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29
let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
- let mut _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+ let mut _2: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+ let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ let mut _4: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+ let mut _5: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+ let mut _6: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++ let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
scope 1 {
debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
- StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
- _2 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+ StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+ Deinit(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+ StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+ StorageLive(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+ StorageLive(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+ _6 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+- switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
- }
-
- bb1: {
-+ StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ _3 = move _2; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
-- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
-- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+- _5 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35
+- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
- }
-
- bb2: {
-- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
-- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+- _5 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
+- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
- }
-
- bb3: {
-+ _1 = Ne(_3, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-+ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ StorageLive(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ _7 = move _6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ _5 = Ne(_7, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
++ StorageDead(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+ StorageDead(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
+- switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+- }
+-
+- bb4: {
+- _4 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+- }
+-
+- bb5: {
+- _4 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+- }
+-
+- bb6: {
++ StorageLive(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++ _8 = move _5; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++ _4 = Ne(_8, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
++ StorageDead(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+ StorageDead(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76
+- switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+- }
+-
+- bb7: {
+- _3 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17
+- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+- }
+-
+- bb8: {
+- _3 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
+- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+- }
+-
+- bb9: {
+- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+- }
+-
+- bb10: {
++ StorageLive(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ _9 = move _4; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ _3 = Ne(_9, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
++ StorageDead(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ StorageLive(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
++ _10 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+- }
+-
+- bb11: {
+- StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+- StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+- }
+-
+- bb12: {
++ _1 = Ne(_10, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
++ StorageDead(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7
_0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8
StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2
return; // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2
fn match_nested_if() -> bool {
let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29
let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
- let mut _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+ let mut _2: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+ let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ let mut _4: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+ let mut _5: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+ let mut _6: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++ let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
scope 1 {
debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
- StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
- _2 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+ StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+ Deinit(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+ StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+ StorageLive(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+ StorageLive(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+ _6 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+- switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
- }
-
- bb1: {
-+ StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ _3 = move _2; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
-- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
-- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+- _5 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35
+- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
- }
-
- bb2: {
-- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
-- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+- _5 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
+- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
- }
-
- bb3: {
-+ _1 = Ne(_3, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-+ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ StorageLive(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ _7 = move _6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ _5 = Ne(_7, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
++ StorageDead(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+ StorageDead(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
+- switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+- }
+-
+- bb4: {
+- _4 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+- }
+-
+- bb5: {
+- _4 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+- }
+-
+- bb6: {
++ StorageLive(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++ _8 = move _5; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++ _4 = Ne(_8, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
++ StorageDead(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+ StorageDead(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76
+- switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+- }
+-
+- bb7: {
+- _3 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17
+- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+- }
+-
+- bb8: {
+- _3 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
+- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+- }
+-
+- bb9: {
+- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+- }
+-
+- bb10: {
++ StorageLive(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ _9 = move _4; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ _3 = Ne(_9, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
++ StorageDead(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ StorageLive(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
++ _10 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+- }
+-
+- bb11: {
+- StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+- StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+- }
+-
+- bb12: {
++ _1 = Ne(_10, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
++ StorageDead(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7
_0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8
StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2
return; // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2
+// unit-test: MatchBranchSimplification
+
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
-// EMIT_MIR matches_reduce_branches.foo.PreCodegen.before.mir
// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
+// unit-test: MatchBranchSimplification
+
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR matches_u8.exhaustive_match.MatchBranchSimplification.diff
// EMIT_MIR matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
scope 1 {
debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
scope 2 {
- scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:25:8: 25:10
debug residual => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
let _16: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
let mut _17: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
scope 4 {
}
}
- scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:25:8: 25:10
debug self => _4; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
let mut _10: isize; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
let _11: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
use std::ops::ControlFlow;
// EMIT_MIR separate_const_switch.too_complex.SeparateConstSwitch.diff
-// EMIT_MIR separate_const_switch.too_complex.ConstProp.diff
-// EMIT_MIR separate_const_switch.too_complex.PreCodegen.after.mir
fn too_complex(x: Result<i32, usize>) -> Option<i32> {
// The pass should break the outer match into
// two blocks that only have one parent each.
}
// EMIT_MIR separate_const_switch.identity.SeparateConstSwitch.diff
-// EMIT_MIR separate_const_switch.identity.ConstProp.diff
-// EMIT_MIR separate_const_switch.identity.PreCodegen.after.mir
fn identity(x: Result<i32, i32>) -> Result<i32, i32> {
Ok(x?)
}
// compile-flags: -Zmir-opt-level=3
// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// This pass is broken since deaggregation changed
+// ignore-test
+
enum Src {
Foo(u8),
Bar,
// EMIT_MIR simplify_arm.id_try.SimplifyArmIdentity.diff
// EMIT_MIR simplify_arm.id_try.SimplifyBranchSame.diff
+// This pass is broken since deaggregation changed
+// ignore-test
+
fn id(o: Option<u8>) -> Option<u8> {
match o {
Some(v) => Some(v),
-// compile-flags: -Zunsound-mir-opts
+// unit-test: SimplifyLocals
fn map(x: Option<Box<()>>) -> Option<Box<()>> {
match x {
+++ /dev/null
-- // MIR for `id` before SimplifyArmIdentity
-+ // MIR for `id` after SimplifyArmIdentity
-
- fn id(_1: Option<u8>) -> Option<u8> {
- debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:7: +0:8
- let mut _0: std::option::Option<u8>; // return place in scope 0 at $DIR/simplify-arm.rs:+0:25: +0:35
- let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:16
- let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
- let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:25: +2:26
- scope 1 {
- debug v => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:14: +2:15
- }
-
- bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
- switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12
- }
-
- bb1: {
- Deinit(_0); // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
- discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
- }
-
- bb3: {
- StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
- _3 = ((_1 as Some).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
- StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26
- _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26
- Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
- ((_0 as Some).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
- discriminant(_0) = 1; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
- StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:26: +2:27
- StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27
- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27
- }
-
- bb4: {
- return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2
- }
- }
-
+++ /dev/null
-- // MIR for `id` before SimplifyBranchSame
-+ // MIR for `id` after SimplifyBranchSame
-
- fn id(_1: Option<u8>) -> Option<u8> {
- debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:7: +0:8
- let mut _0: std::option::Option<u8>; // return place in scope 0 at $DIR/simplify-arm.rs:+0:25: +0:35
- let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:16
- let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
- let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:25: +2:26
- scope 1 {
- debug v => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:14: +2:15
- }
-
- bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
- switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12
- }
-
- bb1: {
- Deinit(_0); // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
- discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
- }
-
- bb3: {
- StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
- _3 = ((_1 as Some).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
- StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26
- _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26
- Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
- ((_0 as Some).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
- discriminant(_0) = 1; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
- StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:26: +2:27
- StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27
- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27
- }
-
- bb4: {
- return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2
- }
- }
-
+++ /dev/null
-- // MIR for `id_result` before SimplifyArmIdentity
-+ // MIR for `id_result` after SimplifyArmIdentity
-
- fn id_result(_1: Result<u8, i32>) -> Result<u8, i32> {
- debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:14: +0:15
- let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:+0:37: +0:52
- let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:14
- let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
- let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:21: +2:22
- let _5: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
- let mut _6: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:23: +3:24
- scope 1 {
- debug x => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:12: +2:13
- }
- scope 2 {
- debug y => _5; // in scope 2 at $DIR/simplify-arm.rs:+3:13: +3:14
- }
-
- bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
- switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12
- }
-
- bb1: {
- StorageLive(_5); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
- _5 = ((_1 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
- StorageLive(_6); // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24
- _6 = _5; // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24
- Deinit(_0); // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
- ((_0 as Err).0: i32) = move _6; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
- discriminant(_0) = 1; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
- StorageDead(_6); // scope 2 at $DIR/simplify-arm.rs:+3:24: +3:25
- StorageDead(_5); // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25
- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
- }
-
- bb3: {
- StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
- _3 = ((_1 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
- StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22
- _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22
- Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
- ((_0 as Ok).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
- discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
- StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:22: +2:23
- StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23
- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23
- }
-
- bb4: {
- return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2
- }
- }
-
+++ /dev/null
-- // MIR for `id_result` before SimplifyBranchSame
-+ // MIR for `id_result` after SimplifyBranchSame
-
- fn id_result(_1: Result<u8, i32>) -> Result<u8, i32> {
- debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:14: +0:15
- let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:+0:37: +0:52
- let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:14
- let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
- let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:21: +2:22
- let _5: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
- let mut _6: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:23: +3:24
- scope 1 {
- debug x => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:12: +2:13
- }
- scope 2 {
- debug y => _5; // in scope 2 at $DIR/simplify-arm.rs:+3:13: +3:14
- }
-
- bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
- switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12
- }
-
- bb1: {
- StorageLive(_5); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
- _5 = ((_1 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
- StorageLive(_6); // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24
- _6 = _5; // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24
- Deinit(_0); // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
- ((_0 as Err).0: i32) = move _6; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
- discriminant(_0) = 1; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
- StorageDead(_6); // scope 2 at $DIR/simplify-arm.rs:+3:24: +3:25
- StorageDead(_5); // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25
- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
- }
-
- bb3: {
- StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
- _3 = ((_1 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
- StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22
- _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22
- Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
- ((_0 as Ok).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
- discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
- StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:22: +2:23
- StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23
- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23
- }
-
- bb4: {
- return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2
- }
- }
-
+++ /dev/null
-- // MIR for `main` before SimplifyArmIdentity
-+ // MIR for `main` after SimplifyArmIdentity
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +0:11
- let _1: Src; // in scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
- let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:+2:18: +5:6
- let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:9: +3:20
- let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
- scope 1 {
- debug e => _1; // in scope 1 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
- let _4: u8; // in scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
- scope 2 {
- }
- scope 3 {
- debug x => _4; // in scope 3 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
- Deinit(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
- ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
- discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
- StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +5:6
- _3 = const 0_isize; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25
- goto -> bb3; // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +2:25
- }
-
- bb1: {
- Deinit(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
- ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
- discriminant(_2) = 0; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
- goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
- }
-
- bb2: {
- unreachable; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25
- }
-
- bb3: {
- StorageLive(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
- _4 = ((_1 as Foo).0: u8); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
- StorageLive(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
- _5 = _4; // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
- Deinit(_2); // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
- ((_2 as Foo).0: u8) = move _5; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
- discriminant(_2) = 0; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
- StorageDead(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
- StorageDead(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
- goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
- }
-
- bb4: {
- StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+5:6: +5:7
- nop; // scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +6:2
- StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+6:1: +6:2
- return; // scope 0 at $DIR/simplify-arm-identity.rs:+6:2: +6:2
- }
- }
-
+++ /dev/null
-- // MIR for `main` before SimplifyArmIdentity
-+ // MIR for `main` after SimplifyArmIdentity
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +0:11
- let _1: Src; // in scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
- let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:+2:18: +5:6
- let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:9: +3:20
- let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
- scope 1 {
- debug e => _1; // in scope 1 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
- let _4: u8; // in scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
- scope 2 {
- }
- scope 3 {
- debug x => _4; // in scope 3 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
- Deinit(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
- ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
- discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
- StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +5:6
- _3 = const 0_isize; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25
- goto -> bb3; // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +2:25
- }
-
- bb1: {
- Deinit(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
- ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
- discriminant(_2) = 0; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
- goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
- }
-
- bb2: {
- unreachable; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25
- }
-
- bb3: {
- StorageLive(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
- _4 = ((_1 as Foo).0: u8); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
- StorageLive(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
- _5 = _4; // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
- Deinit(_2); // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
- ((_2 as Foo).0: u8) = move _5; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
- discriminant(_2) = 0; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
- StorageDead(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
- StorageDead(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
- goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
- }
-
- bb4: {
- StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+5:6: +5:7
- nop; // scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +6:2
- StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+6:1: +6:2
- return; // scope 0 at $DIR/simplify-arm-identity.rs:+6:2: +6:2
- }
- }
-
debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9
let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46
let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13
-- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
+ let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
scope 1 {
- debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
}
bb0: {
+- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
+- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
_2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12
}
bb1: {
- ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
+ _4 = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
+ ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
+ StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
+ StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
}
}
bb4: {
+- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2
}
}
debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9
let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46
let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13
-- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
+ let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
scope 1 {
- debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
}
bb0: {
+- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
+- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
_2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12
}
bb1: {
- ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
+ _4 = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
+ ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
+ StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
+ StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
}
}
bb4: {
+- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2
}
}
+++ /dev/null
-// compile-flags: -Zunsound-mir-opts
-// EMIT_MIR simplify_try.try_identity.SimplifyArmIdentity.diff
-// EMIT_MIR simplify_try.try_identity.SimplifyBranchSame.after.mir
-// EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir
-// EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff
-
-
-fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> {
- r
-}
-
-fn from_error<T, E>(e: E) -> Result<T, E> {
- Err(e)
-}
-
-// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure,
-// so the relevant desugar is copied inline in order to keep the test testing the same thing.
-// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR
-// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not.
-fn try_identity(x: Result<u32, i32>) -> Result<u32, i32> {
- let y = match into_result(x) {
- Err(e) => return from_error(From::from(e)),
- Ok(v) => v,
- };
- Ok(y)
-}
-
-fn main() {
- let _ = try_identity(Ok(0));
-}
--- /dev/null
+// MIR for `new` after PreCodegen
+
+fn new(_1: Result<T, E>) -> Result<T, E> {
+ debug x => _1; // in scope 0 at $DIR/try_identity_e2e.rs:+0:14: +0:15
+ let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46
+ let mut _2: T; // in scope 0 at $DIR/try_identity_e2e.rs:+2:9: +10:10
+ let mut _3: std::ops::ControlFlow<E, T>; // in scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
+ let mut _4: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:22
+ let _5: T; // in scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
+ let mut _6: T; // in scope 0 at $DIR/try_identity_e2e.rs:+4:48: +4:49
+ let _7: E; // in scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
+ let mut _8: E; // in scope 0 at $DIR/try_identity_e2e.rs:+5:46: +5:47
+ let mut _9: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+8:13: +8:37
+ let _10: T; // in scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
+ let _11: E; // in scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
+ let mut _12: E; // in scope 0 at $DIR/try_identity_e2e.rs:+9:49: +9:50
+ scope 1 {
+ debug v => _5; // in scope 1 at $DIR/try_identity_e2e.rs:+4:20: +4:21
+ }
+ scope 2 {
+ debug e => _7; // in scope 2 at $DIR/try_identity_e2e.rs:+5:21: +5:22
+ }
+ scope 3 {
+ debug v => _10; // in scope 3 at $DIR/try_identity_e2e.rs:+8:35: +8:36
+ }
+ scope 4 {
+ debug e => _11; // in scope 4 at $DIR/try_identity_e2e.rs:+9:32: +9:33
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +10:10
+ StorageLive(_3); // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
+ _4 = discriminant(_1); // scope 0 at $DIR/try_identity_e2e.rs:+3:19: +3:20
+ switchInt(move _4) -> [0_isize: bb2, 1_isize: bb1, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:20
+ }
+
+ bb1: {
+ StorageLive(_7); // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
+ _7 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
+ StorageLive(_8); // scope 2 at $DIR/try_identity_e2e.rs:+5:46: +5:47
+ _8 = move _7; // scope 2 at $DIR/try_identity_e2e.rs:+5:46: +5:47
+ Deinit(_3); // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
+ ((_3 as Break).0: E) = move _8; // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
+ discriminant(_3) = 1; // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
+ StorageDead(_8); // scope 2 at $DIR/try_identity_e2e.rs:+5:47: +5:48
+ StorageDead(_7); // scope 0 at $DIR/try_identity_e2e.rs:+5:47: +5:48
+ _9 = discriminant(_3); // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
+ switchInt(move _9) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10
+ }
+
+ bb2: {
+ StorageLive(_5); // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
+ _5 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
+ StorageLive(_6); // scope 1 at $DIR/try_identity_e2e.rs:+4:48: +4:49
+ _6 = move _5; // scope 1 at $DIR/try_identity_e2e.rs:+4:48: +4:49
+ Deinit(_3); // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
+ ((_3 as Continue).0: T) = move _6; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
+ discriminant(_3) = 0; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
+ StorageDead(_6); // scope 1 at $DIR/try_identity_e2e.rs:+4:49: +4:50
+ StorageDead(_5); // scope 0 at $DIR/try_identity_e2e.rs:+4:49: +4:50
+ _9 = discriminant(_3); // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
+ switchInt(move _9) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10
+ }
+
+ bb3: {
+ StorageLive(_11); // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
+ _11 = move ((_3 as Break).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
+ StorageLive(_12); // scope 4 at $DIR/try_identity_e2e.rs:+9:49: +9:50
+ _12 = move _11; // scope 4 at $DIR/try_identity_e2e.rs:+9:49: +9:50
+ Deinit(_0); // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
+ ((_0 as Err).0: E) = move _12; // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
+ discriminant(_0) = 1; // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
+ StorageDead(_12); // scope 4 at $DIR/try_identity_e2e.rs:+9:50: +9:51
+ StorageDead(_11); // scope 0 at $DIR/try_identity_e2e.rs:+9:50: +9:51
+ StorageDead(_2); // scope 0 at $DIR/try_identity_e2e.rs:+11:5: +11:6
+ StorageDead(_3); // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
+ return; // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
+ }
+
+ bb4: {
+ unreachable; // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
+ }
+
+ bb5: {
+ StorageLive(_10); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
+ _10 = move ((_3 as Continue).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
+ _2 = move _10; // scope 3 at $DIR/try_identity_e2e.rs:+8:41: +8:42
+ StorageDead(_10); // scope 0 at $DIR/try_identity_e2e.rs:+8:41: +8:42
+ Deinit(_0); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
+ ((_0 as Ok).0: T) = move _2; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
+ discriminant(_0) = 0; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
+ StorageDead(_2); // scope 0 at $DIR/try_identity_e2e.rs:+11:5: +11:6
+ StorageDead(_3); // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
+ return; // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
+ }
+}
--- /dev/null
+// MIR for `old` after PreCodegen
+
+fn old(_1: Result<T, E>) -> Result<T, E> {
+ debug x => _1; // in scope 0 at $DIR/try_identity_e2e.rs:+0:14: +0:15
+ let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46
+ let mut _2: T; // in scope 0 at $DIR/try_identity_e2e.rs:+2:9: +5:10
+ let mut _3: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:18
+ let _4: T; // in scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
+ let _5: E; // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
+ let mut _6: E; // in scope 0 at $DIR/try_identity_e2e.rs:+4:34: +4:35
+ scope 1 {
+ debug v => _4; // in scope 1 at $DIR/try_identity_e2e.rs:+3:16: +3:17
+ }
+ scope 2 {
+ debug e => _5; // in scope 2 at $DIR/try_identity_e2e.rs:+4:17: +4:18
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +5:10
+ _3 = discriminant(_1); // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +2:16
+ switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +2:16
+ }
+
+ bb1: {
+ StorageLive(_5); // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
+ _5 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
+ StorageLive(_6); // scope 2 at $DIR/try_identity_e2e.rs:+4:34: +4:35
+ _6 = move _5; // scope 2 at $DIR/try_identity_e2e.rs:+4:34: +4:35
+ Deinit(_0); // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
+ ((_0 as Err).0: E) = move _6; // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
+ discriminant(_0) = 1; // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
+ StorageDead(_6); // scope 2 at $DIR/try_identity_e2e.rs:+4:35: +4:36
+ StorageDead(_5); // scope 0 at $DIR/try_identity_e2e.rs:+4:35: +4:36
+ StorageDead(_2); // scope 0 at $DIR/try_identity_e2e.rs:+6:5: +6:6
+ return; // scope 0 at $DIR/try_identity_e2e.rs:+7:1: +7:2
+ }
+
+ bb2: {
+ unreachable; // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +2:16
+ }
+
+ bb3: {
+ StorageLive(_4); // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
+ _4 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
+ _2 = move _4; // scope 1 at $DIR/try_identity_e2e.rs:+3:22: +3:23
+ StorageDead(_4); // scope 0 at $DIR/try_identity_e2e.rs:+3:22: +3:23
+ Deinit(_0); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
+ ((_0 as Ok).0: T) = move _2; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
+ discriminant(_0) = 0; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
+ StorageDead(_2); // scope 0 at $DIR/try_identity_e2e.rs:+6:5: +6:6
+ return; // scope 0 at $DIR/try_identity_e2e.rs:+7:1: +7:2
+ }
+}
--- /dev/null
+// Track the status of MIR optimizations simplifying `Ok(res?)` for both the old and new desugarings
+// of that syntax.
+
+use std::ops::ControlFlow;
+
+// EMIT_MIR try_identity_e2e.new.PreCodegen.after.mir
+fn new<T, E>(x: Result<T, E>) -> Result<T, E> {
+ Ok(
+ match {
+ match x {
+ Ok(v) => ControlFlow::Continue(v),
+ Err(e) => ControlFlow::Break(e),
+ }
+ } {
+ ControlFlow::Continue(v) => v,
+ ControlFlow::Break(e) => return Err(e),
+ }
+ )
+}
+
+// EMIT_MIR try_identity_e2e.old.PreCodegen.after.mir
+fn old<T, E>(x: Result<T, E>) -> Result<T, E> {
+ Ok(
+ match x {
+ Ok(v) => v,
+ Err(e) => return Err(e),
+ }
+ )
+}
+
+fn main() {
+ let _ = new::<(), ()>(Ok(()));
+ let _ = old::<(), ()>(Ok(()));
+}
--- /dev/null
+// This test ensures that the "item-info" looks about the same
+// whether or not it's inside a toggle.
+goto: file://|DOC_PATH|/lib2/struct.ItemInfoAlignmentTest.html
+
+// First, we try it in "desktop" mode.
+size: (1200, 870)
+compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x"))
+// Next, we try it in "mobile" mode (max-width: 700px).
+size: (650, 650)
+compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x"))
assert-css: (
".search-input",
{
- "border-color": "rgb(240, 240, 240)",
+ "border-color": "rgb(224, 224, 224)",
"background-color": "rgb(240, 240, 240)",
"color": "rgb(17, 17, 17)",
},
+++ /dev/null
-// Ensures that the search input border color changes on focus.
-goto: file://|DOC_PATH|/test_docs/index.html
-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
-reload:
-
-assert-css: (".search-input", {"border-color": "rgb(240, 240, 240)"})
-click: ".search-input"
-assert-css: (".search-input", {"border-color": "rgb(0, 141, 253)"})
-
-local-storage: {"rustdoc-theme": "light"}
-reload:
-
-assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"})
-click: ".search-input"
-assert-css: (".search-input", {"border-color": "rgb(102, 175, 233)"})
-
-local-storage: {"rustdoc-theme": "ayu"}
-reload:
-
-assert-css: (".search-input", {"border-color": "rgb(92, 103, 115)"})
-click: ".search-input"
-assert-css: (".search-input", {"border-color": "rgb(92, 103, 115)"})
/// Some docs.
#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "emscripten", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
impl SimpleTrait for LongItemInfo2 {}
+
+pub struct WhereWhitespace<T>;
+
+impl<T> WhereWhitespace<T> {
+ pub fn new<F>(f: F) -> Self
+ where
+ F: FnMut() -> i32,
+ {}
+}
+
+impl<K, T> Whitespace<&K> for WhereWhitespace<T>
+where
+ K: std::fmt::Debug,
+{
+ type Output = WhereWhitespace<T>;
+ fn index(&self, _key: &K) -> &Self::Output {
+ self
+ }
+}
+
+pub trait Whitespace<Idx>
+where
+ Idx: ?Sized,
+{
+ type Output;
+ fn index(&self, index: Idx) -> &Self::Output;
+}
+
+pub struct ItemInfoAlignmentTest;
+
+impl ItemInfoAlignmentTest {
+ /// This method has docs
+ #[deprecated]
+ pub fn foo() {}
+ #[deprecated]
+ pub fn bar() {}
+}
size: (600, 600)
goto: file://|DOC_PATH|/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html
// It shouldn't have an overflow in the topbar either.
-assert-property: (".mobile-topbar .location", {"scrollWidth": "492"})
-assert-property: (".mobile-topbar .location", {"clientWidth": "492"})
+assert-property: (".mobile-topbar .location", {"scrollWidth": "502"})
+assert-property: (".mobile-topbar .location", {"clientWidth": "502"})
assert-css: (".mobile-topbar .location", {"overflow-x": "hidden"})
--- /dev/null
+// This test ensures that the where conditions are correctly displayed.
+goto: file://|DOC_PATH|/lib2/trait.Whitespace.html
+show-text: true
+// First, we check in the trait definition if the where clause is "on its own" (not on the same
+// line than "pub trait Whitespace<Idx>").
+compare-elements-position-false: (".item-decl code", ".where.fmt-newline", ("y"))
+// And that the code following it isn't on the same line either.
+compare-elements-position-false: (".item-decl .fnname", ".where.fmt-newline", ("y"))
+
+goto: file://|DOC_PATH|/lib2/struct.WhereWhitespace.html
+// We make the screen a bit wider to ensure that the trait impl is on one line.
+size: (915, 915)
+
+compare-elements-position-false: ("#method\.new .fnname", "#method\.new .where.fmt-newline", ("y"))
+// We ensure that both the trait name and the struct name are on the same line in
+// "impl<K, T> Whitespace<&K> for WhereWhitespace<T>".
+compare-elements-position: (
+ "#trait-implementations-list .impl h3 .trait",
+ "#trait-implementations-list .impl h3 .struct",
+ ("y"),
+)
+// And we now check that the where condition isn't on the same line.
+compare-elements-position-false: (
+ "#trait-implementations-list .impl h3 .trait",
+ "#trait-implementations-list .impl h3 .where.fmt-newline",
+ ("y"),
+)
--- /dev/null
+#[repr(i8)]
+pub enum Ordering {
+ // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.expr" '"-1"'
+ // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.value" '"-1"'
+ Less = -1,
+ // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.expr" '"0"'
+ // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.value" '"0"'
+ Equal = 0,
+ // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.expr" '"1"'
+ // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.value" '"1"'
+ Greater = 1,
+}
--- /dev/null
+pub enum Foo {
+ // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.value" '"0"'
+ // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.expr" '"{ _ }"'
+ Addition = 0 + 0,
+ // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.value" '"1"'
+ // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.expr" '"0b1"'
+ Bin = 0b1,
+ // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.value" '"2"'
+ // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.expr" '"0o2"'
+ Oct = 0o2,
+ // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.value" '"3"'
+ // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.expr" '"THREE"'
+ PubConst = THREE,
+ // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.value" '"4"'
+ // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.expr" '"0x4"'
+ Hex = 0x4,
+ // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.value" '"5"'
+ // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.expr" '"{ _ }"'
+ Cast = 5 as isize,
+ // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.value" '"6"'
+ // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.expr" '"{ _ }"'
+ PubCall = six(),
+ // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.value" '"7"'
+ // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.expr" '"{ _ }"'
+ PrivCall = seven(),
+ // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.value" '"8"'
+ // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.expr" '"EIGHT"'
+ PrivConst = EIGHT,
+}
+
+pub const THREE: isize = 3;
+const EIGHT: isize = 8;
+
+pub const fn six() -> isize {
+ 6
+}
+const fn seven() -> isize {
+ 7
+}
--- /dev/null
+// ignore-tidy-linelength
+#![feature(repr128)]
+#![allow(incomplete_features)]
+
+#[repr(u64)]
+pub enum U64 {
+ // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.value" '"0"'
+ // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.expr" '"u64::MIN"'
+ U64Min = u64::MIN,
+ // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.value" '"18446744073709551615"'
+ // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.expr" '"u64::MAX"'
+ U64Max = u64::MAX,
+}
+
+#[repr(i64)]
+pub enum I64 {
+ // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.value" '"-9223372036854775808"'
+ // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.expr" '"i64::MIN"'
+ I64Min = i64::MIN,
+ // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.value" '"9223372036854775807"'
+ // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.expr" '"i64::MAX"'
+ I64Max = i64::MAX,
+}
+
+#[repr(u128)]
+pub enum U128 {
+ // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.value" '"0"'
+ // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.expr" '"u128::MIN"'
+ U128Min = u128::MIN,
+ // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.value" '"340282366920938463463374607431768211455"'
+ // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.expr" '"u128::MAX"'
+ U128Max = u128::MAX,
+}
+
+#[repr(i128)]
+pub enum I128 {
+ // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.value" '"-170141183460469231731687303715884105728"'
+ // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.expr" '"i128::MIN"'
+ I128Min = i128::MIN,
+ // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.value" '"170141183460469231731687303715884105727"'
+ // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.expr" '"i128::MAX"'
+ I128Max = i128::MAX,
+}
--- /dev/null
+#[repr(u32)]
+pub enum Foo {
+ // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.value" '"0"'
+ // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.expr" '"0"'
+ Basic = 0,
+ // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.value" '"10"'
+ // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.expr" '"10u32"'
+ Suffix = 10u32,
+ // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.value" '"100"'
+ // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.expr" '"1_0_0"'
+ Underscore = 1_0_0,
+ // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.value" '"1000"'
+ // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.expr" '"1_0_0_0u32"'
+ SuffixUnderscore = 1_0_0_0u32,
+}
--- /dev/null
+pub enum Foo {
+ // @is "$.index[*][?(@.name=='Has')].inner.variant_inner" '{"expr":"0", "value":"0"}'
+ Has = 0,
+ // @is "$.index[*][?(@.name=='Doesnt')].inner.variant_inner" null
+ Doesnt,
+ // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant_inner" null
+ AlsoDoesnt,
+ // @is "$.index[*][?(@.name=='AlsoHas')].inner.variant_inner" '{"expr":"44", "value":"44"}'
+ AlsoHas = 44,
+}
impl<const N: usize> Trait<N> for [u8; N] {}
// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
-// 'pub struct Foo<const N: usize> where u8: Trait<N>'
+// 'pub struct Foo<const N: usize>where u8: Trait<N>'
pub struct Foo<const N: usize> where u8: Trait<N>;
// @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
pub struct Bar<T, const N: usize>([T; N]);
-// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
+// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M>where u8: Trait<M>'
impl<const M: usize> Foo<M> where u8: Trait<M> {
// @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
pub const FOO_ASSOC: usize = M + 13;
// @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8%2C%20M%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>'
impl<const M: usize> Bar<u8, M> {
// @has - '//*[@id="method.hey"]' \
- // 'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
+ // 'pub fn hey<const N: usize>(&self) -> Foo<N>where u8: Trait<N>'
pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N> {
Foo
}
}
// @has foo/fn.test.html '//pre[@class="rust fn"]' \
-// 'pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N>'
+// 'pub fn test<const N: usize>() -> impl Trait<N>where u8: Trait<N>'
pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N> {
2u8
}
--- /dev/null
+// Regression test for <https://github.com/rust-lang/rust/issues/101129>.
+
+#![feature(doc_auto_cfg)]
+#![crate_type = "lib"]
+#![crate_name = "foo"]
+
+pub struct S;
+pub trait MyTrait1 {}
+pub trait MyTrait2 {}
+
+// @has foo/struct.S.html
+// @has - '//*[@id="impl-MyTrait1-for-S"]//*[@class="stab portability"]' \
+// 'Available on non-crate feature coolstuff only.'
+#[cfg(not(feature = "coolstuff"))]
+impl MyTrait1 for S {}
+
+#[cfg(not(feature = "coolstuff"))]
+mod submod {
+ use crate::{S, MyTrait2};
+ // This impl should also have the `not(feature = "coolstuff")`.
+ // @has - '//*[@id="impl-MyTrait2-for-S"]//*[@class="stab portability"]' \
+ // 'Available on non-crate feature coolstuff only.'
+ impl MyTrait2 for S {}
+}
// @has foo/trait.LendingIterator.html
pub trait LendingIterator {
- // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a"
+ // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a"
type Item<'a> where Self: 'a;
// @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]' \
pub struct Infinite<T>(T);
// @has foo/trait.LendingIterator.html
-// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a = &'a T"
+// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a = &'a T"
impl<T> LendingIterator for Infinite<T> {
type Item<'a> where Self: 'a = &'a T;
pub trait Trait<'x> {}
// @has foo/fn.test1.html
-// @has - '//pre' "pub fn test1<T>() where for<'a> &'a T: Iterator,"
+// @has - '//pre' "pub fn test1<T>()where for<'a> &'a T: Iterator,"
pub fn test1<T>()
where
for<'a> &'a T: Iterator,
}
// @has foo/fn.test2.html
-// @has - '//pre' "pub fn test2<T>() where for<'a, 'b> &'a T: Trait<'b>,"
+// @has - '//pre' "pub fn test2<T>()where for<'a, 'b> &'a T: Trait<'b>,"
pub fn test2<T>()
where
for<'a, 'b> &'a T: Trait<'b>,
}
// @has foo/fn.test3.html
-// @has - '//pre' "pub fn test3<F>() where F: for<'a, 'b> Fn(&'a u8, &'b u8),"
+// @has - '//pre' "pub fn test3<F>()where F: for<'a, 'b> Fn(&'a u8, &'b u8),"
pub fn test3<F>()
where
F: for<'a, 'b> Fn(&'a u8, &'b u8),
// @has - '//span[@id="structfield.some_trait"]' "some_trait: &'a dyn for<'b> Trait<'b>"
impl<'a> Foo<'a> {
- // @has - '//h4[@class="code-header"]' "pub fn bar<T>() where T: Trait<'a>,"
+ // @has - '//h4[@class="code-header"]' "pub fn bar<T>()where T: Trait<'a>,"
pub fn bar<T>()
where
T: Trait<'a>,
pub struct Foo<T> { field: T }
// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
+// "impl<T: Clone> !AnAutoTrait for Foo<T>where T: Sync,"
// @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
-// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
+// "impl<T: Clone> !AnAutoTrait for Foo<T>where T: Sync,"
impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync {}
pub mod reexport {
// @has issue_20727_4/reexport/trait.Index.html
- // @has - '//*[@class="rust trait"]' 'trait Index<Idx> where Idx: ?Sized, {'
+ // @has - '//*[@class="rust trait"]' 'trait Index<Idx>where Idx: ?Sized,{'
// @has - '//*[@class="rust trait"]' 'type Output: ?Sized'
// @has - '//*[@class="rust trait"]' \
// 'fn index(&self, index: Idx) -> &Self::Output'
// @has issue_20727_4/reexport/trait.IndexMut.html
// @has - '//*[@class="rust trait"]' \
- // 'trait IndexMut<Idx>: Index<Idx> where Idx: ?Sized, {'
+ // 'trait IndexMut<Idx>: Index<Idx>where Idx: ?Sized,{'
// @has - '//*[@class="rust trait"]' \
// 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
pub use issue_20727::IndexMut;
// @has issue_21801/struct.Foo.html
// @has - '//*[@id="method.new"]' \
-// 'fn new<F>(f: F) -> Foo where F: FnMut() -> i32'
+// 'fn new<F>(f: F) -> Foowhere F: FnMut() -> i32'
pub use issue_21801::Foo;
fn my_string(&self) -> String;
}
-// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug"
+// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header in-band']" "impl<T> MyTrait for Twhere T: Debug"
impl<T> MyTrait for T
where
T: fmt::Debug,
pub trait Bar {}
-// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T) where T: Bar;'
+// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T)where T: Bar;'
pub struct Foo<T>(pub T) where T: Bar;
}
// @has issue_50159/struct.Switch.html
-// @has - '//h3[@class="code-header in-band"]' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send'
-// @has - '//h3[@class="code-header in-band"]' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync'
+// @has - '//h3[@class="code-header in-band"]' 'impl<B> Send for Switch<B>where <B as Signal>::Item: Send'
+// @has - '//h3[@class="code-header in-band"]' 'impl<B> Sync for Switch<B>where <B as Signal>::Item: Sync'
// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
pub struct Switch<B: Signal> {
// @has issue_51236/struct.Owned.html
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<T> Send for Owned<T> where <T as Owned<'static>>::Reader: Send"
+// "impl<T> Send for Owned<T>where <T as Owned<'static>>::Reader: Send"
pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
}
pub trait ScopeHandle<'scope> {}
-
-
// @has issue_54705/struct.ScopeFutureContents.html
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'scope, S> Send for ScopeFutureContents<'scope, S> where S: Sync"
+// "impl<'scope, S> Send for ScopeFutureContents<'scope, S>where S: Sync"
//
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S> where S: Sync"
+// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S>where S: Sync"
pub struct ScopeFutureContents<'scope, S>
where S: ScopeHandle<'scope>,
{
extern crate issue_98697_reexport_with_anonymous_lifetime;
-// @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro<F>() where F: Fn(&str)'
+// @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro<F>()where F: Fn(&str)'
// @!has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'for<'
pub use issue_98697_reexport_with_anonymous_lifetime::repro;
// @has - '//span[@class="in-band"]' 'Primitive Type slice'
// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
-// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T] where T: Send'
-// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T] where T: Sync'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T]where T: Send'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T]where T: Sync'
#[doc(primitive = "slice")]
/// this is a test!
mod slice_prim {}
// @has basic/struct.Foo.html
-// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Foo<T> where T: Send'
-// @has - '//h3[@class="code-header in-band"]' 'impl<T> Sync for Foo<T> where T: Sync'
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Foo<T>where T: Send'
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Sync for Foo<T>where T: Sync'
// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
pub struct Foo<T> {
// @has complex/struct.NotOuter.html
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
+// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \
// -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter};
// @has lifetimes/struct.Foo.html
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'c, K> Send for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
+// "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
//
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'c, K> Sync for Foo<'c, K> where K: Sync"
+// "impl<'c, K> Sync for Foo<'c, K>where K: Sync"
pub struct Foo<'c, K: 'c> {
inner_field: Inner<'c, K>,
}
// @has manual/struct.Foo.html
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// 'impl<T> Sync for Foo<T> where T: Sync'
+// 'impl<T> Sync for Foo<T>where T: Sync'
//
// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// 'impl<T> Send for Foo<T>'
// @has nested/struct.Foo.html
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// 'impl<T> Send for Foo<T> where T: Copy'
+// 'impl<T> Send for Foo<T>where T: Copy'
//
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// 'impl<T> Sync for Foo<T> where T: Sync'
+// 'impl<T> Sync for Foo<T>where T: Sync'
pub struct Foo<T> {
inner_field: Inner<T>,
}
// @has no_redundancy/struct.Outer.html
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<T> Send for Outer<T> where T: Send + Copy"
+// "impl<T> Send for Outer<T>where T: Send + Copy"
pub struct Outer<T> {
inner_field: Inner<T>,
}
// @has project/struct.Foo.html
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'c, K> Send for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
+// "impl<'c, K> Send for Foo<'c, K>where K: MyTrait<MyItem = bool>, 'c: 'static"
//
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'c, K> Sync for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
+// "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
// 'c: 'static,"
pub struct Foo<'c, K: 'c> {
inner_field: Inner<'c, K>,
// @has self_referential/struct.WriteAndThen.html
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<P1> Send for WriteAndThen<P1> where <P1 as Pattern>::Value: Send"
+// "impl<P1> Send for WriteAndThen<P1>where <P1 as Pattern>::Value: Send"
pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
where P1: Pattern;
// @has static_region/struct.Owned.html
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<T> Send for Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
+// "impl<T> Send for Owned<T>where <T as OwnedTrait<'static>>::Reader: Send"
pub struct Owned<T> where T: OwnedTrait<'static> {
marker: <T as OwnedTrait<'static>>::Reader,
}
}
// @has 'foo/trait.SomeTrait.html'
-// @has - "//*[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
+// @has - "//*[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)
where
A: PartialOrd<A> + PartialEq<A>,
pub trait MyTrait { fn dummy(&self) { } }
-// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait"
+// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_)where A: MyTrait"
pub struct Alpha<A>(A) where A: MyTrait;
-// @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B> where B: MyTrait"
+// @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B>where B: MyTrait"
pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); }
-// @has foo/fn.charlie.html '//pre' "pub fn charlie<C>() where C: MyTrait"
+// @has foo/fn.charlie.html '//pre' "pub fn charlie<C>()where C: MyTrait"
pub fn charlie<C>() where C: MyTrait {}
pub struct Delta<D>(D);
// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<D> Delta<D> where D: MyTrait"
+// "impl<D> Delta<D>where D: MyTrait"
impl<D> Delta<D> where D: MyTrait {
pub fn delta() {}
}
}
// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<E> MyTrait for Echo<E> where E: MyTrait"
+// "impl<E> MyTrait for Echo<E>where E: MyTrait"
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
-// "impl<E> MyTrait for Echo<E> where E: MyTrait"
-impl<E> MyTrait for Echo<E> where E: MyTrait {}
+// "impl<E> MyTrait for Echo<E>where E: MyTrait"
+impl<E> MyTrait for Echo<E>where E: MyTrait {}
pub enum Foxtrot<F> { Foxtrot1(F) }
// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
+// "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
-// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
-impl<F> MyTrait for Foxtrot<F> where F: MyTrait {}
+// "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
+impl<F> MyTrait for Foxtrot<F>where F: MyTrait {}
// @has foo/type.Golf.html '//pre[@class="rust typedef"]' \
-// "type Golf<T> where T: Clone, = (T, T)"
+// "type Golf<T>where T: Clone, = (T, T)"
pub type Golf<T> where T: Clone = (T, T);
// Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)]
// normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr"
-
+// normalize-stderr-test "diagnostic_builder\.rs:[0-9]+:[0-9]+" -> "diagnostic_builder.rs:LL:CC"
// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
// changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler
// the test is just ignored on stable and beta:
|
= help: normalized in stderr
note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
- --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:569:19
+ --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
|
LL | arg: impl IntoDiagnosticArg,
| ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
#[derive(SessionSubdiagnostic)]
enum Q {
#[bar]
-//~^ ERROR `#[bar]` is not a valid attribute
-//~^^ ERROR cannot find attribute `bar` in this scope
+ //~^ ERROR `#[bar]` is not a valid attribute
+ //~^^ ERROR cannot find attribute `bar` in this scope
A {
#[primary_span]
span: Span,
#[derive(SessionSubdiagnostic)]
enum R {
#[bar = "..."]
-//~^ ERROR `#[bar = ...]` is not a valid attribute
-//~^^ ERROR cannot find attribute `bar` in this scope
+ //~^ ERROR `#[bar = ...]` is not a valid attribute
+ //~^^ ERROR cannot find attribute `bar` in this scope
A {
#[primary_span]
span: Span,
#[derive(SessionSubdiagnostic)]
enum S {
#[bar = 4]
-//~^ ERROR `#[bar = ...]` is not a valid attribute
-//~^^ ERROR cannot find attribute `bar` in this scope
+ //~^ ERROR `#[bar = ...]` is not a valid attribute
+ //~^^ ERROR cannot find attribute `bar` in this scope
A {
#[primary_span]
span: Span,
#[derive(SessionSubdiagnostic)]
enum T {
#[bar("...")]
-//~^ ERROR `#[bar("...")]` is not a valid attribute
-//~^^ ERROR cannot find attribute `bar` in this scope
+ //~^ ERROR `#[bar(...)]` is not a valid attribute
+ //~^^ ERROR cannot find attribute `bar` in this scope
A {
#[primary_span]
span: Span,
#[derive(SessionSubdiagnostic)]
enum U {
#[label(code = "...")]
-//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
+ //~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
A {
#[primary_span]
span: Span,
var: String,
},
B {
-//~^ ERROR subdiagnostic kind not specified
+ //~^ ERROR subdiagnostic kind not specified
#[primary_span]
span: Span,
var: String,
b: u64
}
+#[derive(SessionSubdiagnostic)]
+#[label(parser::add_paren)]
+#[label(parser::add_paren)]
+struct AD {
+ #[primary_span]
+ span: Span,
+}
+
#[derive(SessionSubdiagnostic)]
#[label(parser::add_paren, parser::add_paren)]
//~^ ERROR `#[label(parser::add_paren)]` is not a valid attribute
#[label(parser::add_paren)]
struct AF {
#[primary_span]
-//~^ NOTE previously specified here
+ //~^ NOTE previously specified here
span_a: Span,
#[primary_span]
-//~^ ERROR specified multiple times
+ //~^ ERROR specified multiple times
span_b: Span,
}
#[derive(SessionSubdiagnostic)]
struct AG {
-//~^ ERROR subdiagnostic kind not specified
+ //~^ ERROR subdiagnostic kind not specified
#[primary_span]
span: Span,
}
#[primary_span]
span: Span,
#[applicability]
-//~^ NOTE previously specified here
+ //~^ NOTE previously specified here
applicability_a: Applicability,
#[applicability]
-//~^ ERROR specified multiple times
+ //~^ ERROR specified multiple times
applicability_b: Applicability,
}
#[derive(SessionSubdiagnostic)]
#[suggestion(parser::add_paren, code = "...")]
-//~^ ERROR suggestion without `applicability`
struct AL {
#[primary_span]
span: Span,
#[applicability]
-//~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability`
+ //~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability`
applicability: Span,
}
#[derive(SessionSubdiagnostic)]
#[suggestion(parser::add_paren, code = "...")]
-//~^ ERROR suggestion without `applicability`
struct AM {
#[primary_span]
span: Span,
#[derive(SessionSubdiagnostic)]
#[suggestion(parser::add_paren, code = "...")]
-//~^ ERROR suggestion without `applicability`
-//~^^ ERROR suggestion without `#[primary_span]` field
+//~^ ERROR suggestion without `#[primary_span]` field
struct AR {
var: String,
}
#[primary_span]
span: Span,
}
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(parser::add_paren, code = "...")]
+//~^ ERROR suggestion without `#[primary_span]` field
+struct BA {
+ #[suggestion_part]
+ //~^ ERROR `#[suggestion_part]` is not a valid attribute
+ span: Span,
+ #[suggestion_part(code = "...")]
+ //~^ ERROR `#[suggestion_part(...)]` is not a valid attribute
+ span2: Span,
+ #[applicability]
+ applicability: Applicability,
+ var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
+//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
+//~| ERROR `code` is not a valid nested attribute of a `multipart_suggestion` attribute
+struct BBa {
+ var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+struct BBb {
+ #[suggestion_part]
+ //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
+ span1: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+struct BBc {
+ #[suggestion_part()]
+ //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
+ span1: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren)]
+//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
+struct BC {
+ #[primary_span]
+ //~^ ERROR `#[primary_span]` is not a valid attribute
+ span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren)]
+struct BD {
+ #[suggestion_part]
+ //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
+ span1: Span,
+ #[suggestion_part()]
+ //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
+ span2: Span,
+ #[suggestion_part(foo = "bar")]
+ //~^ ERROR `#[suggestion_part(foo = ...)]` is not a valid attribute
+ span4: Span,
+ #[suggestion_part(code = "...")]
+ //~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+ s1: String,
+ #[suggestion_part()]
+ //~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+ s2: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+struct BE {
+ #[suggestion_part(code = "...", code = ",,,")]
+ //~^ ERROR specified multiple times
+ //~| NOTE previously specified here
+ span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+struct BF {
+ #[suggestion_part(code = "(")]
+ first: Span,
+ #[suggestion_part(code = ")")]
+ second: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren)]
+struct BG {
+ #[applicability]
+ appl: Applicability,
+ #[suggestion_part(code = "(")]
+ first: Span,
+ #[suggestion_part(code = ")")]
+ second: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+//~^ NOTE previously specified here
+struct BH {
+ #[applicability]
+ //~^ ERROR specified multiple times
+ appl: Applicability,
+ #[suggestion_part(code = "(")]
+ first: Span,
+ #[suggestion_part(code = ")")]
+ second: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+struct BI {
+ #[suggestion_part(code = "")]
+ spans: Vec<Span>,
+}
| ^^^^^^^^^^
error: `code` is not a valid nested attribute of a `label` attribute
- --> $DIR/subdiagnostic-derive.rs:137:1
+ --> $DIR/subdiagnostic-derive.rs:137:28
|
LL | #[label(parser::add_paren, code = "...")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^
error: `applicability` is not a valid nested attribute of a `label` attribute
- --> $DIR/subdiagnostic-derive.rs:146:1
+ --> $DIR/subdiagnostic-derive.rs:146:28
|
LL | #[label(parser::add_paren, applicability = "machine-applicable")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: unsupported type attribute for subdiagnostic enum
--> $DIR/subdiagnostic-derive.rs:155:1
LL | #[bar = 4]
| ^^^^^^^^^^
-error: `#[bar("...")]` is not a valid attribute
- --> $DIR/subdiagnostic-derive.rs:205:11
+error: `#[bar(...)]` is not a valid attribute
+ --> $DIR/subdiagnostic-derive.rs:205:5
|
LL | #[bar("...")]
- | ^^^^^
- |
- = help: first argument of the attribute should be the diagnostic slug
+ | ^^^^^^^^^^^^^
error: diagnostic slug must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive.rs:217:5
|
LL | #[bar("...")]
| ^^^^^^^^^^^^^
+ |
+ = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
error: unexpected unsupported untagged union
--> $DIR/subdiagnostic-derive.rs:304:1
| |_^
error: `#[label(parser::add_paren)]` is not a valid attribute
- --> $DIR/subdiagnostic-derive.rs:311:28
+ --> $DIR/subdiagnostic-derive.rs:319:28
|
LL | #[label(parser::add_paren, parser::add_paren)]
| ^^^^^^^^^^^^^^^^^
= help: a diagnostic slug must be the first argument to the attribute
error: specified multiple times
- --> $DIR/subdiagnostic-derive.rs:324:5
+ --> $DIR/subdiagnostic-derive.rs:332:5
|
LL | #[primary_span]
| ^^^^^^^^^^^^^^^
|
note: previously specified here
- --> $DIR/subdiagnostic-derive.rs:321:5
+ --> $DIR/subdiagnostic-derive.rs:329:5
|
LL | #[primary_span]
| ^^^^^^^^^^^^^^^
error: subdiagnostic kind not specified
- --> $DIR/subdiagnostic-derive.rs:330:8
+ --> $DIR/subdiagnostic-derive.rs:338:8
|
LL | struct AG {
| ^^
error: specified multiple times
- --> $DIR/subdiagnostic-derive.rs:367:47
+ --> $DIR/subdiagnostic-derive.rs:375:47
|
LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
| ^^^^^^^^^^^^
|
note: previously specified here
- --> $DIR/subdiagnostic-derive.rs:367:33
+ --> $DIR/subdiagnostic-derive.rs:375:33
|
LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
| ^^^^^^^^^^^^
error: specified multiple times
- --> $DIR/subdiagnostic-derive.rs:385:5
+ --> $DIR/subdiagnostic-derive.rs:393:5
|
LL | #[applicability]
| ^^^^^^^^^^^^^^^^
|
note: previously specified here
- --> $DIR/subdiagnostic-derive.rs:382:5
+ --> $DIR/subdiagnostic-derive.rs:390:5
|
LL | #[applicability]
| ^^^^^^^^^^^^^^^^
error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
- --> $DIR/subdiagnostic-derive.rs:396:5
+ --> $DIR/subdiagnostic-derive.rs:403:5
|
LL | #[applicability]
| ^^^^^^^^^^^^^^^^
-error: suggestion without `applicability`
- --> $DIR/subdiagnostic-derive.rs:391:1
+error: suggestion without `code = "..."`
+ --> $DIR/subdiagnostic-derive.rs:416:1
|
-LL | / #[suggestion(parser::add_paren, code = "...")]
-LL | |
-LL | | struct AL {
-LL | | #[primary_span]
-... |
-LL | | applicability: Span,
-LL | | }
- | |_^
+LL | #[suggestion(parser::add_paren)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: suggestion without `applicability`
- --> $DIR/subdiagnostic-derive.rs:402:1
+error: invalid applicability
+ --> $DIR/subdiagnostic-derive.rs:426:46
+ |
+LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")]
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: suggestion without `#[primary_span]` field
+ --> $DIR/subdiagnostic-derive.rs:444:1
|
LL | / #[suggestion(parser::add_paren, code = "...")]
LL | |
-LL | | struct AM {
-LL | | #[primary_span]
-LL | | span: Span,
+LL | | struct AR {
+LL | | var: String,
LL | | }
| |_^
-error: suggestion without `code = "..."`
- --> $DIR/subdiagnostic-derive.rs:410:1
+error: unsupported type attribute for subdiagnostic enum
+ --> $DIR/subdiagnostic-derive.rs:458:1
|
-LL | / #[suggestion(parser::add_paren)]
+LL | #[label]
+ | ^^^^^^^^
+
+error: `var` doesn't refer to a field on this type
+ --> $DIR/subdiagnostic-derive.rs:478:39
+ |
+LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+ | ^^^^^^^
+
+error: `var` doesn't refer to a field on this type
+ --> $DIR/subdiagnostic-derive.rs:497:43
+ |
+LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+ | ^^^^^^^
+
+error: `#[suggestion_part]` is not a valid attribute
+ --> $DIR/subdiagnostic-derive.rs:520:5
+ |
+LL | #[suggestion_part]
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
+
+error: `#[suggestion_part(...)]` is not a valid attribute
+ --> $DIR/subdiagnostic-derive.rs:523:5
+ |
+LL | #[suggestion_part(code = "...")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: `#[suggestion_part(...)]` is only valid in multipart suggestions
+
+error: suggestion without `#[primary_span]` field
+ --> $DIR/subdiagnostic-derive.rs:517:1
+ |
+LL | / #[suggestion(parser::add_paren, code = "...")]
LL | |
-LL | | struct AN {
-LL | | #[primary_span]
+LL | | struct BA {
+LL | | #[suggestion_part]
... |
-LL | | applicability: Applicability,
+LL | | var: String,
LL | | }
| |_^
-error: invalid applicability
- --> $DIR/subdiagnostic-derive.rs:420:46
+error: `code` is not a valid nested attribute of a `multipart_suggestion` attribute
+ --> $DIR/subdiagnostic-derive.rs:532:43
|
-LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")]
- | ^^^^^^^^^^^^^^^^^^^^^
+LL | #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
+ | ^^^^^^^^^^^^
-error: suggestion without `applicability`
- --> $DIR/subdiagnostic-derive.rs:438:1
+error: multipart suggestion without any `#[suggestion_part(...)]` fields
+ --> $DIR/subdiagnostic-derive.rs:532:1
|
-LL | / #[suggestion(parser::add_paren, code = "...")]
+LL | / #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
LL | |
LL | |
-LL | | struct AR {
+LL | | struct BBa {
LL | | var: String,
LL | | }
| |_^
-error: suggestion without `#[primary_span]` field
- --> $DIR/subdiagnostic-derive.rs:438:1
+error: `#[suggestion_part(...)]` attribute without `code = "..."`
+ --> $DIR/subdiagnostic-derive.rs:542:5
|
-LL | / #[suggestion(parser::add_paren, code = "...")]
+LL | #[suggestion_part]
+ | ^^^^^^^^^^^^^^^^^^
+
+error: `#[suggestion_part(...)]` attribute without `code = "..."`
+ --> $DIR/subdiagnostic-derive.rs:550:5
+ |
+LL | #[suggestion_part()]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: `#[primary_span]` is not a valid attribute
+ --> $DIR/subdiagnostic-derive.rs:559:5
+ |
+LL | #[primary_span]
+ | ^^^^^^^^^^^^^^^
+ |
+ = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
+
+error: multipart suggestion without any `#[suggestion_part(...)]` fields
+ --> $DIR/subdiagnostic-derive.rs:556:1
+ |
+LL | / #[multipart_suggestion(parser::add_paren)]
LL | |
+LL | | struct BC {
+LL | | #[primary_span]
LL | |
-LL | | struct AR {
-LL | | var: String,
+LL | | span: Span,
LL | | }
| |_^
-error: unsupported type attribute for subdiagnostic enum
- --> $DIR/subdiagnostic-derive.rs:453:1
+error: `#[suggestion_part(...)]` attribute without `code = "..."`
+ --> $DIR/subdiagnostic-derive.rs:567:5
|
-LL | #[label]
- | ^^^^^^^^
+LL | #[suggestion_part]
+ | ^^^^^^^^^^^^^^^^^^
-error: `var` doesn't refer to a field on this type
- --> $DIR/subdiagnostic-derive.rs:473:39
+error: `#[suggestion_part(...)]` attribute without `code = "..."`
+ --> $DIR/subdiagnostic-derive.rs:570:5
|
-LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
- | ^^^^^^^
+LL | #[suggestion_part()]
+ | ^^^^^^^^^^^^^^^^^^^^
-error: `var` doesn't refer to a field on this type
- --> $DIR/subdiagnostic-derive.rs:492:43
+error: `#[suggestion_part(foo = ...)]` is not a valid attribute
+ --> $DIR/subdiagnostic-derive.rs:573:23
|
-LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
- | ^^^^^^^
+LL | #[suggestion_part(foo = "bar")]
+ | ^^^^^^^^^^^
+ |
+ = help: `code` is the only valid nested attribute
+
+error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+ --> $DIR/subdiagnostic-derive.rs:576:5
+ |
+LL | #[suggestion_part(code = "...")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+ --> $DIR/subdiagnostic-derive.rs:579:5
+ |
+LL | #[suggestion_part()]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: specified multiple times
+ --> $DIR/subdiagnostic-derive.rs:587:37
+ |
+LL | #[suggestion_part(code = "...", code = ",,,")]
+ | ^^^^^^^^^^^^
+ |
+note: previously specified here
+ --> $DIR/subdiagnostic-derive.rs:587:23
+ |
+LL | #[suggestion_part(code = "...", code = ",,,")]
+ | ^^^^^^^^^^^^
+
+error: specified multiple times
+ --> $DIR/subdiagnostic-derive.rs:617:5
+ |
+LL | #[applicability]
+ | ^^^^^^^^^^^^^^^^
+ |
+note: previously specified here
+ --> $DIR/subdiagnostic-derive.rs:614:43
+ |
+LL | #[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: cannot find attribute `foo` in this scope
--> $DIR/subdiagnostic-derive.rs:63:3
LL | #[label(slug)]
| ^^^^ not found in `rustc_errors::fluent`
-error: aborting due to 50 previous errors
+error: aborting due to 63 previous errors
For more information about this error, try `rustc --explain E0425`.
help: remove the extra argument
|
LL | extra();
- | ~~~~~~~
+ | ~~
error[E0061]: this function takes 1 argument but 0 arguments were supplied
--> $DIR/basic.rs:22:5
help: provide the argument
|
LL | missing(/* u32 */);
- | ~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~
error[E0308]: arguments to this function are incorrect
--> $DIR/basic.rs:23:5
help: swap these arguments
|
LL | swapped(1, "");
- | ~~~~~~~~~~~~~~
+ | ~~~~~~~
error[E0308]: arguments to this function are incorrect
--> $DIR/basic.rs:24:5
help: reorder these arguments
|
LL | permuted(X {}, Y {}, Z {});
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~
error[E0057]: this function takes 1 argument but 0 arguments were supplied
--> $DIR/basic.rs:27:5
help: provide the argument
|
LL | closure(/* value */);
- | ~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~
error: aborting due to 6 previous errors
help: did you mean
|
LL | complex(/* u32 */, &"", /* E */, F::X2, G{}, X {}, Y {}, Z {});
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
help: remove the extra argument
|
LL | t();
- | ~~~
+ | ~~
error[E0057]: this function takes 0 arguments but 1 argument was supplied
--> $DIR/exotic-calls.rs:7:5
help: remove the extra argument
|
LL | t();
- | ~~~
+ | ~~
error[E0057]: this function takes 0 arguments but 1 argument was supplied
--> $DIR/exotic-calls.rs:16:5
help: remove the extra argument
|
LL | baz()()
- |
+ | ~~
error[E0057]: this function takes 0 arguments but 1 argument was supplied
--> $DIR/exotic-calls.rs:22:5
help: remove the extra argument
|
LL | x();
- | ~~~
+ | ~~
error: aborting due to 4 previous errors
help: remove the extra argument
|
LL | empty();
- | ~~~~~~~
+ | ~~
error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/extra_arguments.rs:9:3
help: remove the extra argument
|
LL | one_arg(1);
- | ~~~~~~~~~~
+ | ~~~
error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/extra_arguments.rs:10:3
help: remove the extra argument
|
LL | one_arg(1);
- | ~~~~~~~~~~
+ | ~~~
error[E0061]: this function takes 1 argument but 3 arguments were supplied
--> $DIR/extra_arguments.rs:11:3
help: remove the extra arguments
|
LL | one_arg(1);
- | ~~~~~~~~~~
+ | ~~~
error[E0061]: this function takes 2 arguments but 3 arguments were supplied
--> $DIR/extra_arguments.rs:13:3
help: remove the extra argument
|
LL | two_arg_same(1, 1);
- | ~~~~~~~~~~~~~~~~~~
+ | ~~~~~~
error[E0061]: this function takes 2 arguments but 3 arguments were supplied
--> $DIR/extra_arguments.rs:14:3
help: remove the extra argument
|
LL | two_arg_same(1, 1);
- | ~~~~~~~~~~~~~~~~~~
+ | ~~~~~~
error[E0061]: this function takes 2 arguments but 3 arguments were supplied
--> $DIR/extra_arguments.rs:16:3
help: remove the extra argument
|
LL | two_arg_diff(1, "");
- | ~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~
error[E0061]: this function takes 2 arguments but 3 arguments were supplied
--> $DIR/extra_arguments.rs:17:3
help: remove the extra argument
|
LL | two_arg_diff(1, "");
- | ~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~
error[E0061]: this function takes 2 arguments but 4 arguments were supplied
--> $DIR/extra_arguments.rs:18:3
help: remove the extra arguments
|
LL | two_arg_diff(1, "");
- | ~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~
error[E0061]: this function takes 2 arguments but 4 arguments were supplied
--> $DIR/extra_arguments.rs:19:3
help: remove the extra arguments
|
LL | two_arg_diff(1, "");
- | ~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~
error[E0061]: this function takes 2 arguments but 3 arguments were supplied
--> $DIR/extra_arguments.rs:22:3
help: remove the extra argument
|
LL | two_arg_same(1, 1);
- | ~~~~~~~~~~~~~~~~~~
+ | ~~~~~~
error[E0061]: this function takes 2 arguments but 3 arguments were supplied
--> $DIR/extra_arguments.rs:23:3
help: remove the extra argument
|
LL | two_arg_diff(1, "");
- | ~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~
error[E0061]: this function takes 2 arguments but 3 arguments were supplied
--> $DIR/extra_arguments.rs:24:3
help: remove the extra argument
|
LL | two_arg_same(1, 1);
- | ~~~~~~~~~~~~~~~~~~
+ | ~~~~~~
error[E0061]: this function takes 2 arguments but 3 arguments were supplied
--> $DIR/extra_arguments.rs:30:3
help: remove the extra argument
|
LL | two_arg_diff(1, "");
- | ~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~
error: aborting due to 14 previous errors
help: provide the argument
|
LL | f(/* usize */, &x, /* usize */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
help: provide the arguments
|
LL | g((), /* bool */, /* bool */, /* bool */, /* bool */, ());
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
help: remove the extra arguments
|
LL | foo(&&A, D, /* &E */, G);
- | ~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
help: provide the argument
|
LL | (|_, ()| ())(if true {} else {return;}, ());
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
help: provide the argument
|
LL | (|_, ()| ())([return, ()], ());
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
help: provide the argument
|
LL | let _f = f((), main);
- | ~~~~~~~~~~~
+ | ~~~~~~~~~~
error: aborting due to previous error
help: provide the argument
|
LL | one_arg(/* i32 */);
- | ~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~
error[E0061]: this function takes 2 arguments but 0 arguments were supplied
--> $DIR/missing_arguments.rs:14:3
help: provide the arguments
|
LL | two_same(/* i32 */, /* i32 */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 2 arguments but 1 argument was supplied
--> $DIR/missing_arguments.rs:15:3
help: provide the argument
|
LL | two_same(1, /* i32 */);
- | ~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~
error[E0061]: this function takes 2 arguments but 0 arguments were supplied
--> $DIR/missing_arguments.rs:16:3
help: provide the arguments
|
LL | two_diff(/* i32 */, /* f32 */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 2 arguments but 1 argument was supplied
--> $DIR/missing_arguments.rs:17:3
help: provide the argument
|
LL | two_diff(1, /* f32 */);
- | ~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~
error[E0061]: this function takes 2 arguments but 1 argument was supplied
--> $DIR/missing_arguments.rs:18:3
help: provide the argument
|
LL | two_diff(/* i32 */, 1.0);
- | ~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 0 arguments were supplied
--> $DIR/missing_arguments.rs:21:3
help: provide the arguments
|
LL | three_same(/* i32 */, /* i32 */, /* i32 */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 1 argument was supplied
--> $DIR/missing_arguments.rs:22:3
help: provide the arguments
|
LL | three_same(1, /* i32 */, /* i32 */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 2 arguments were supplied
--> $DIR/missing_arguments.rs:23:3
help: provide the argument
|
LL | three_same(1, 1, /* i32 */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 2 arguments were supplied
--> $DIR/missing_arguments.rs:26:3
help: provide the argument
|
LL | three_diff(/* i32 */, 1.0, "");
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 2 arguments were supplied
--> $DIR/missing_arguments.rs:27:3
help: provide the argument
|
LL | three_diff(1, /* f32 */, "");
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 2 arguments were supplied
--> $DIR/missing_arguments.rs:28:3
help: provide the argument
|
LL | three_diff(1, 1.0, /* &str */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 1 argument was supplied
--> $DIR/missing_arguments.rs:29:3
help: provide the arguments
|
LL | three_diff(/* i32 */, /* f32 */, "");
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 1 argument was supplied
--> $DIR/missing_arguments.rs:30:3
help: provide the arguments
|
LL | three_diff(/* i32 */, 1.0, /* &str */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 1 argument was supplied
--> $DIR/missing_arguments.rs:31:3
help: provide the arguments
|
LL | three_diff(1, /* f32 */, /* &str */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 4 arguments but 0 arguments were supplied
--> $DIR/missing_arguments.rs:34:3
help: provide the arguments
|
LL | four_repeated(/* i32 */, /* f32 */, /* f32 */, /* &str */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 4 arguments but 2 arguments were supplied
--> $DIR/missing_arguments.rs:35:3
help: provide the arguments
|
LL | four_repeated(1, /* f32 */, /* f32 */, "");
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 5 arguments but 0 arguments were supplied
--> $DIR/missing_arguments.rs:38:3
help: provide the arguments
|
LL | complex(/* i32 */, /* f32 */, /* i32 */, /* f32 */, /* &str */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 5 arguments but 2 arguments were supplied
--> $DIR/missing_arguments.rs:39:3
help: provide the arguments
|
LL | complex(1, /* f32 */, /* i32 */, /* f32 */, "");
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 19 previous errors
help: remove the extra argument
|
LL | two_args(1, /* f32 */);
- | ~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 4 arguments were supplied
--> $DIR/mixed_cases.rs:11:3
help: did you mean
|
LL | three_args(1, /* f32 */, "");
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 2 arguments were supplied
--> $DIR/mixed_cases.rs:14:3
help: provide the argument
|
LL | three_args(1, /* f32 */, /* &str */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0308]: arguments to this function are incorrect
--> $DIR/mixed_cases.rs:17:3
help: did you mean
|
LL | three_args(1, /* f32 */, "");
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~
error[E0308]: arguments to this function are incorrect
--> $DIR/mixed_cases.rs:20:3
help: swap these arguments
|
LL | three_args(1, /* f32 */, "");
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 3 arguments but 2 arguments were supplied
--> $DIR/mixed_cases.rs:23:3
help: did you mean
|
LL | three_args(1, /* f32 */, "");
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~
error: aborting due to 6 previous errors
help: reorder these arguments
|
LL | three_args(1, 1.0, "");
- | ~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~
error[E0308]: arguments to this function are incorrect
--> $DIR/permuted_arguments.rs:12:3
help: reorder these arguments
|
LL | many_args(1, 1.0, "", X {}, Y {});
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors
help: swap these arguments
|
LL | two_args(1, 1.0);
- | ~~~~~~~~~~~~~~~~
+ | ~~~~~~~~
error[E0308]: arguments to this function are incorrect
--> $DIR/swapped_arguments.rs:9:3
help: swap these arguments
|
LL | three_args(1, 1.0, "");
- | ~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~
error[E0308]: arguments to this function are incorrect
--> $DIR/swapped_arguments.rs:10:3
help: swap these arguments
|
LL | three_args(1, 1.0, "");
- | ~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~
error[E0308]: arguments to this function are incorrect
--> $DIR/swapped_arguments.rs:11:3
help: swap these arguments
|
LL | three_args(1, 1.0, "");
- | ~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~
error[E0308]: arguments to this function are incorrect
--> $DIR/swapped_arguments.rs:13:3
help: did you mean
|
LL | four_args(1, 1.0, "", X {});
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~
error: aborting due to 5 previous errors
--- /dev/null
+// check-pass
+// compile-flags: -Zunpretty=expanded
+core::arch::global_asm!("x: .byte 42");
--- /dev/null
+#![feature(prelude_import)]
+#![no_std]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+// check-pass
+// compile-flags: -Zunpretty=expanded
+global_asm! ("x: .byte 42");
f1(2u32, 4u32);
//~^ ERROR `u32: Foo` is not satisfied
//~| 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
+ //~| ERROR `u32: Foo` is not satisfied
}
pub fn f2_int() {
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:29:5
+ |
+LL | f1(2u32, 4u32);
+ | ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u32`
+ |
+ = help: the trait `Foo` is implemented for `i32`
+
error[E0277]: the trait bound `u32: Foo` is not satisfied
--> $DIR/associated-types-path-2.rs:29:14
|
= help: the trait `Foo` is implemented for `i32`
error[E0277]: the trait bound `u32: Foo` is not satisfied
- --> $DIR/associated-types-path-2.rs:35:8
+ --> $DIR/associated-types-path-2.rs:36:8
|
LL | f1(2u32, 4i32);
| -- ^^^^ the trait `Foo` is not implemented for `u32`
| ^^^ required by this bound in `f1`
error[E0277]: the trait bound `u32: Foo` is not satisfied
- --> $DIR/associated-types-path-2.rs:35:14
+ --> $DIR/associated-types-path-2.rs:36:5
+ |
+LL | f1(2u32, 4i32);
+ | ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u32`
+ |
+ = help: the trait `Foo` is implemented for `i32`
+
+error[E0277]: the trait bound `u32: Foo` is not satisfied
+ --> $DIR/associated-types-path-2.rs:36:14
|
LL | f1(2u32, 4i32);
| ^^^^ the trait `Foo` is not implemented for `u32`
= help: the trait `Foo` is implemented for `i32`
error[E0308]: mismatched types
- --> $DIR/associated-types-path-2.rs:41:18
+ --> $DIR/associated-types-path-2.rs:43:18
|
LL | let _: i32 = f2(2i32);
| --- ^^^^^^^^ expected `i32`, found `u32`
LL | let _: i32 = f2(2i32).try_into().unwrap();
| ++++++++++++++++++++
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
// run-pass
// edition:2018
+// revisions: normal drop-tracking
+// [normal]compile-flags: -Zdrop-tracking=no
+// [drop-tracking]compile-flags: -Zdrop-tracking
#![allow(dead_code)]
use std::future::Future;
LL | (|_| 2333).await;
| ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future
|
- = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]`
+ = help: the trait `Future` is not implemented for closure `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]`
= note: [closure@$DIR/issue-62009-1.rs:12:6: 12:9] must be a future or must implement `IntoFuture` to be awaited
= note: required for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` to implement `IntoFuture`
help: remove the `.await`
--- /dev/null
+// issue #100631, make sure `TyCtxt::get_attr` only called by case that compiler
+// can reasonably deal with multiple attributes.
+// `repr` will use `TyCtxt::get_attrs` since it's `DuplicatesOk`.
+#[repr(C)] //~ ERROR: unsupported representation for zero-variant enum [E0084]
+#[repr(C)]
+enum Foo {}
+
+fn main() {}
--- /dev/null
+error[E0084]: unsupported representation for zero-variant enum
+ --> $DIR/issue-100631.rs:4:1
+ |
+LL | #[repr(C)]
+ | ^^^^^^^^^^
+LL | #[repr(C)]
+LL | enum Foo {}
+ | -------- zero-variant enum
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0084`.
--- /dev/null
+#![feature(rustc_private)]
+extern crate libc;
+
+/// So tests don't have to bring libc in scope themselves
+pub enum SignalHandler {
+ Ignore,
+ Default,
+}
+
+/// Helper to assert that [`libc::SIGPIPE`] has the expected signal handler.
+pub fn assert_sigpipe_handler(expected_handler: SignalHandler) {
+ #[cfg(unix)]
+ #[cfg(not(any(
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "horizon",
+ target_os = "android",
+ )))]
+ {
+ let prev = unsafe { libc::signal(libc::SIGPIPE, libc::SIG_IGN) };
+
+ let expected = match expected_handler {
+ SignalHandler::Ignore => libc::SIG_IGN,
+ SignalHandler::Default => libc::SIG_DFL,
+ };
+ assert_eq!(prev, expected);
+
+ // Unlikely to matter, but restore the old value anyway
+ unsafe { libc::signal(libc::SIGPIPE, prev); };
+ }
+}
--- /dev/null
+#![feature(unix_sigpipe)]
+#![unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute cannot be used at crate level
+
+fn main() {}
--- /dev/null
+error: `unix_sigpipe` attribute cannot be used at crate level
+ --> $DIR/unix_sigpipe-crate.rs:2:1
+ |
+LL | #![unix_sigpipe = "inherit"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[unix_sigpipe = "inherit"]
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "sig_ign"]
+#[unix_sigpipe = "inherit"] //~ error: multiple `unix_sigpipe` attributes
+fn main() {}
--- /dev/null
+error: multiple `unix_sigpipe` attributes
+ --> $DIR/unix_sigpipe-duplicates.rs:4:1
+ |
+LL | #[unix_sigpipe = "inherit"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+note: attribute also specified here
+ --> $DIR/unix_sigpipe-duplicates.rs:3:1
+ |
+LL | #[unix_sigpipe = "sig_ign"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "sig_ign"]
+fn main() {
+ extern crate sigpipe_utils;
+
+ // #[unix_sigpipe = "sig_ign"] is active, so the legacy behavior of ignoring
+ // SIGPIPE shall be in effect
+ sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
+}
--- /dev/null
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "inherit"]
+fn main() {
+ extern crate sigpipe_utils;
+
+ // #[unix_sigpipe = "inherit"] is active, so SIGPIPE shall NOT be ignored,
+ // instead the default handler shall be installed. (We assume that the
+ // process that runs these tests have the default handler.)
+ sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
+}
--- /dev/null
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe(inherit)] //~ error: malformed `unix_sigpipe` attribute input
+fn main() {}
--- /dev/null
+error: malformed `unix_sigpipe` attribute input
+ --> $DIR/unix_sigpipe-list.rs:3:1
+ |
+LL | #[unix_sigpipe(inherit)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: the following are the possible correct uses
+ |
+LL | #[unix_sigpipe = "inherit|sig_ign|sig_dfl"]
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | #[unix_sigpipe]
+ | ~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
+fn f() {}
+
+fn main() {}
--- /dev/null
+error: `unix_sigpipe` attribute can only be used on `fn main()`
+ --> $DIR/unix_sigpipe-non-main-fn.rs:3:1
+ |
+LL | #[unix_sigpipe = "inherit"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(unix_sigpipe)]
+
+mod m {
+ #[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on root `fn main()`
+ fn main() {}
+}
+
+fn main() {}
--- /dev/null
+error: `unix_sigpipe` attribute can only be used on root `fn main()`
+ --> $DIR/unix_sigpipe-non-root-main.rs:4:5
+ |
+LL | #[unix_sigpipe = "inherit"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+fn main() {
+ extern crate sigpipe_utils;
+
+ // SIGPIPE shall be ignored since #[unix_sigpipe = "..."] is not used
+ sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
+}
--- /dev/null
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+
+fn main() {
+ extern crate sigpipe_utils;
+
+ // Only #![feature(unix_sigpipe)] is enabled, not #[unix_sigpipe = "..."].
+ // This shall not change any behavior, so we still expect SIGPIPE to be
+ // ignored
+ sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
+}
--- /dev/null
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+#![feature(rustc_attrs)]
+
+#[unix_sigpipe = "sig_dfl"]
+#[rustc_main]
+fn rustc_main() {
+ extern crate sigpipe_utils;
+
+ // #[unix_sigpipe = "sig_dfl"] is active, so SIGPIPE handler shall be
+ // SIG_DFL. Note that we have a #[rustc_main], but it should still work.
+ sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
+}
--- /dev/null
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "sig_dfl"]
+fn main() {
+ extern crate sigpipe_utils;
+
+ // #[unix_sigpipe = "sig_dfl"] is active, so SIGPIPE shall NOT be ignored, instead
+ // the default handler shall be installed
+ sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
+}
--- /dev/null
+#![feature(start)]
+#![feature(unix_sigpipe)]
+
+#[start]
+#[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
+fn custom_start(argc: isize, argv: *const *const u8) -> isize { 0 }
--- /dev/null
+error: `unix_sigpipe` attribute can only be used on `fn main()`
+ --> $DIR/unix_sigpipe-start.rs:5:1
+ |
+LL | #[unix_sigpipe = "inherit"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
+struct S;
+
+fn main() {}
--- /dev/null
+error: `unix_sigpipe` attribute can only be used on `fn main()`
+ --> $DIR/unix_sigpipe-struct.rs:3:1
+ |
+LL | #[unix_sigpipe = "inherit"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "wrong"] //~ error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+fn main() {}
--- /dev/null
+error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+ --> $DIR/unix_sigpipe-wrong.rs:3:1
+ |
+LL | #[unix_sigpipe = "wrong"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe] //~ error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+fn main() {}
--- /dev/null
+error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+ --> $DIR/unix_sigpipe.rs:3:1
+ |
+LL | #[unix_sigpipe]
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
LL | assert_eq!(foo, y);
| ^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
- = help: the trait `Debug` is not implemented for `for<'r> fn(&'r i32) -> &'r i32 {foo}`
+ = help: the trait `Debug` is not implemented for fn item `for<'r> fn(&'r i32) -> &'r i32 {foo}`
= help: use parentheses to call the function: `foo(s)`
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
--- /dev/null
+fn main() {
+ let mut vec: Vec<i32> = Vec::new();
+ let closure = move || {
+ vec.clear();
+ let mut iter = vec.iter();
+ move || { iter.next() } //~ ERROR captured variable cannot escape `FnMut` closure bod
+ };
+}
--- /dev/null
+error: captured variable cannot escape `FnMut` closure body
+ --> $DIR/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs:6:9
+ |
+LL | let mut vec: Vec<i32> = Vec::new();
+ | ------- variable defined here
+LL | let closure = move || {
+ | - inferred to be a `FnMut` closure
+LL | vec.clear();
+ | --- variable captured here
+LL | let mut iter = vec.iter();
+LL | move || { iter.next() }
+ | ^^^^^^^^^^^^^^^^^^^^^^^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
+ |
+ = note: `FnMut` closures only have access to their captured variables while they are executing...
+ = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
--- /dev/null
+struct State;
+
+fn once(_: impl FnOnce()) {}
+
+fn fill_memory_blocks_mt(state: &mut State) {
+ loop {
+ once(move || {
+ //~^ ERROR use of moved value: `state`
+ fill_segment(state);
+ });
+ }
+}
+
+fn fill_segment(_: &mut State) {}
+
+fn main() {}
--- /dev/null
+error[E0382]: use of moved value: `state`
+ --> $DIR/issue-101119.rs:7:14
+ |
+LL | fn fill_memory_blocks_mt(state: &mut State) {
+ | ----- move occurs because `state` has type `&mut State`, which does not implement the `Copy` trait
+LL | loop {
+LL | once(move || {
+ | ^^^^^^^ value moved into closure here, in previous iteration of loop
+LL |
+LL | fill_segment(state);
+ | ----- use occurs due to use in closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
help: provide the arguments
|
LL | foo(/* isize */, /* u8 */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~
error[E0060]: this function takes at least 2 arguments but 1 argument was supplied
--> $DIR/variadic-ffi-1.rs:21:9
help: provide the argument
|
LL | foo(1, /* u8 */);
- | ~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~
error[E0308]: mismatched types
--> $DIR/variadic-ffi-1.rs:23:56
--- /dev/null
+// This test check that #![allow(unexpected_cfgs)] works with --cfg
+//
+// check-pass
+// compile-flags: --cfg=unexpected --check-cfg=names() -Z unstable-options
+
+#![allow(unexpected_cfgs)]
+
+fn main() {}
|
= note: expected values for `feature` are: full, serde
-warning: 2 warnings emitted
+warning: unexpected condition value `rand` for condition name `feature`
+ |
+ = help: was set with `--cfg` but isn't in the `--check-cfg` expected values
+
+warning: 3 warnings emitted
// we correctly lint on the `cfg!` macro and `cfg_attr` attribute.
//
// check-pass
-// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --cfg feature="bar" -Z unstable-options
+// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --cfg feature="bar" --cfg unknown_name -Z unstable-options
#[cfg(windows)]
fn do_windows_stuff() {}
LL | #[cfg_attr(uu, test)]
| ^^
+warning: unexpected condition value `bar` for condition name `feature`
+ |
+ = help: was set with `--cfg` but isn't in the `--check-cfg` expected values
+
+warning: unexpected `unknown_name` as condition name
+ |
+ = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
+
warning: unexpected `cfg` condition name
--> $DIR/mix.rs:35:10
|
|
= note: expected values for `feature` are: foo
-warning: 25 warnings emitted
+warning: 27 warnings emitted
| |
| required by a bound introduced by this call
|
- = help: the trait `FnOnce<(&str,)>` is not implemented for `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
+ = help: the trait `FnOnce<(&str,)>` is not implemented for fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `Option::<T>::map`
--> $SRC_DIR/core/src/option.rs:LL:COL
--- /dev/null
+// check-pass
+
+use std::convert::TryFrom;
+
+pub trait FieldElement {
+ type Integer: TryFrom<usize, Error = std::num::TryFromIntError>;
+
+ fn valid_integer_try_from<N>(i: N) -> Result<Self::Integer, ()>
+ where
+ Self::Integer: TryFrom<N>,
+ {
+ Self::Integer::try_from(i).map_err(|_| ())
+ }
+}
+
+fn main() {}
LL | unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
| -------------------------------------------------------------------- inside `core::f32::<impl f32>::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
- | ------------------------------------------------------------------ inside `<fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32} as FnOnce<(f32,)>>::call_once - shim(fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
- ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
-LL | called_in_const.call_once(arg)
- | ------------------------------ inside `const_eval_select::<(f32,), fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32}, [closure@core::f32::<impl f32>::to_bits::{closure#0}], u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
::: $DIR/const-float-bits-reject-conv.rs:27:30
|
LL | const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
LL | unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
| -------------------------------------------------------------------- inside `core::f32::<impl f32>::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
- | ------------------------------------------------------------------ inside `<fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32} as FnOnce<(f32,)>>::call_once - shim(fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
- ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
-LL | called_in_const.call_once(arg)
- | ------------------------------ inside `const_eval_select::<(f32,), fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32}, [closure@core::f32::<impl f32>::to_bits::{closure#0}], u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
::: $DIR/const-float-bits-reject-conv.rs:28:30
|
LL | const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
LL | unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
| -------------------------------------------------------------------- inside `core::f64::<impl f64>::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
- | ------------------------------------------------------------------ inside `<fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64} as FnOnce<(f64,)>>::call_once - shim(fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
- ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
-LL | called_in_const.call_once(arg)
- | ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64}, [closure@core::f64::<impl f64>::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
::: $DIR/const-float-bits-reject-conv.rs:54:30
|
LL | const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
LL | unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
| -------------------------------------------------------------------- inside `core::f64::<impl f64>::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
- | ------------------------------------------------------------------ inside `<fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64} as FnOnce<(f64,)>>::call_once - shim(fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
- ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
-LL | called_in_const.call_once(arg)
- | ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64}, [closure@core::f64::<impl f64>::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
::: $DIR/const-float-bits-reject-conv.rs:55:30
|
LL | const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
help: provide the argument
|
LL | let a = f(/* value */);
- | ~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~
error[E0057]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/E0057.rs:5:13
help: remove the extra argument
|
LL | let c = f(2);
- | ~~~~
+ | ~~~
error: aborting due to 2 previous errors
help: provide the argument
|
LL | unsafe { printf(/* *const u8 */); }
- | ~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~
error: aborting due to previous error
help: provide the argument
|
LL | f(0, /* &str */);
- | ~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~
error[E0061]: this function takes 1 argument but 0 arguments were supplied
--> $DIR/E0061.rs:9:5
help: provide the argument
|
LL | f2(/* u16 */);
- | ~~~~~~~~~~~~~
+ | ~~~~~~~~~~~
error: aborting due to 2 previous errors
| |
| required by a bound introduced by this call
|
- = help: the trait `Fn<()>` is not implemented for `extern "C" fn() {f}`
+ = help: the trait `Fn<()>` is not implemented for fn item `extern "C" fn() {f}`
= note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `is_fn`
--> $DIR/extern-wrong-value-type.rs:4:28
--- /dev/null
+#![crate_type = "bin"]
+
+#[unix_sigpipe = "inherit"] //~ the `#[unix_sigpipe]` attribute is an experimental feature
+fn main () {}
--- /dev/null
+error[E0658]: the `#[unix_sigpipe]` attribute is an experimental feature
+ --> $DIR/feature-gate-unix_sigpipe.rs:3:1
+ |
+LL | #[unix_sigpipe = "inherit"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #97889 <https://github.com/rust-lang/rust/issues/97889> for more information
+ = help: add `#![feature(unix_sigpipe)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
| ^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
+ = note: all function arguments must have a statically known size
= help: unsized fn params are gated as an unstable feature
-help: function arguments must have a statically known size, borrowed types always have a known size
- |
-LL | foo(&*x);
- | +
error: aborting due to 2 previous errors
help: provide the argument
|
LL | f(&[f(/* value */)]);
- | ~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~
error: aborting due to previous error
--- /dev/null
+// See issue #100696.
+// run-fail
+// check-run-results
+fn main() {
+ &""[1..];
+}
--- /dev/null
+thread 'main' panicked at 'byte index 1 is out of bounds of ``', $DIR/const-eval-select-backtrace-std.rs:5:6
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
--- /dev/null
+#![feature(core_intrinsics)]
+// See issue #100696.
+// run-fail
+// check-run-results
+
+#[track_caller]
+fn uhoh() {
+ panic!("Aaah!")
+}
+
+const fn c() {}
+
+fn main() {
+ // safety: this is unsound and just used to test
+ unsafe {
+ std::intrinsics::const_eval_select((), c, uhoh);
+ }
+}
--- /dev/null
+thread 'main' panicked at 'Aaah!', $DIR/const-eval-select-backtrace.rs:16:9
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
const fn not_fn_items() {
const_eval_select((), || {}, || {});
- //~^ ERROR the trait bound
+ //~^ ERROR this argument must be a function item
+ //~| ERROR this argument must be a function item
const_eval_select((), 42, 0xDEADBEEF);
- //~^ ERROR the trait bound
+ //~^ ERROR expected a `FnOnce<()>` closure
//~| ERROR expected a `FnOnce<()>` closure
+ //~| ERROR this argument must be a function item
+ //~| ERROR this argument must be a function item
}
const fn foo(n: i32) -> i32 {
//~^ ERROR type mismatch
}
+const fn non_const_fn() {
+ const_eval_select((1,), bar, bar);
+ //~^ ERROR this argument must be a `const fn`
+}
+
fn main() {}
-error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: FnOnce<()>` is not satisfied
+error: this argument must be a function item
--> $DIR/const-eval-select-bad.rs:7:27
|
LL | const_eval_select((), || {}, || {});
- | ----------------- ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`
- | |
- | required by a bound introduced by this call
+ | ^^^^^
|
- = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`
-note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`, but that implementation is not `const`
- --> $DIR/const-eval-select-bad.rs:7:27
+ = note: expected a function item, found [closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]
+ = help: consult the documentation on `const_eval_select` for more information
+
+error: this argument must be a function item
+ --> $DIR/const-eval-select-bad.rs:7:34
|
LL | const_eval_select((), || {}, || {});
- | ^^^^^
- = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` 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 | F: ~const FnOnce<ARG, Output = RET>,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+ = note: expected a function item, found [closure@$DIR/const-eval-select-bad.rs:7:34: 7:36]
+ = help: consult the documentation on `const_eval_select` for more information
-error[E0277]: the trait bound `{integer}: FnOnce<()>` is not satisfied
- --> $DIR/const-eval-select-bad.rs:9:27
+error: this argument must be a function item
+ --> $DIR/const-eval-select-bad.rs:10:27
+ |
+LL | const_eval_select((), 42, 0xDEADBEEF);
+ | ^^
+ |
+ = note: expected a function item, found {integer}
+ = help: consult the documentation on `const_eval_select` for more information
+
+error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
+ --> $DIR/const-eval-select-bad.rs:10:27
|
LL | const_eval_select((), 42, 0xDEADBEEF);
| ----------------- ^^ expected an `FnOnce<()>` closure, found `{integer}`
| |
| required by a bound introduced by this call
|
- = help: the trait `~const FnOnce<()>` is not implemented for `{integer}`
+ = 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 | F: ~const FnOnce<ARG, Output = RET>,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+LL | F: FnOnce<ARG, Output = RET>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+
+error: this argument must be a function item
+ --> $DIR/const-eval-select-bad.rs:10:31
+ |
+LL | const_eval_select((), 42, 0xDEADBEEF);
+ | ^^^^^^^^^^
+ |
+ = note: expected a function item, found {integer}
+ = help: consult the documentation on `const_eval_select` for more information
error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
- --> $DIR/const-eval-select-bad.rs:9:31
+ --> $DIR/const-eval-select-bad.rs:10:31
|
LL | const_eval_select((), 42, 0xDEADBEEF);
| ----------------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}`
note: required by a bound in `const_eval_select`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
-LL | G: FnOnce<ARG, Output = RET> + ~const Destruct,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+LL | G: FnOnce<ARG, Output = RET>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool`
- --> $DIR/const-eval-select-bad.rs:29:34
+ --> $DIR/const-eval-select-bad.rs:32:34
|
LL | const_eval_select((1,), foo, bar);
| ----------------- ^^^ expected `i32`, found `bool`
note: required by a bound in `const_eval_select`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
-LL | G: FnOnce<ARG, Output = RET> + ~const Destruct,
- | ^^^^^^^^^^^^ required by this bound in `const_eval_select`
+LL | G: FnOnce<ARG, Output = RET>,
+ | ^^^^^^^^^^^^ required by this bound in `const_eval_select`
error[E0631]: type mismatch in function arguments
- --> $DIR/const-eval-select-bad.rs:34:32
+ --> $DIR/const-eval-select-bad.rs:37:32
|
LL | const fn foo(n: i32) -> i32 {
| --------------------------- found signature defined here
note: required by a bound in `const_eval_select`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
-LL | F: ~const FnOnce<ARG, Output = RET>,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+LL | F: FnOnce<ARG, Output = RET>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+
+error: this argument must be a `const fn`
+ --> $DIR/const-eval-select-bad.rs:42:29
+ |
+LL | const_eval_select((1,), bar, bar);
+ | ^^^
+ |
+ = help: consult the documentation on `const_eval_select` for more information
-error: aborting due to 5 previous errors
+error: aborting due to 9 previous errors
Some errors have detailed explanations: E0271, E0277, E0631.
For more information about an error, try `rustc --explain E0271`.
help: remove the extra argument
|
LL | |t| f();
- | ~~~
+ | ~~
error: aborting due to previous error
help: provide the argument
|
LL | print_x(/* &dyn Foo<Item = bool> */, /* &str */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
| -------------------------------------------------- `get_function` defined here returns `&dyn Fn() -> (dyn Trait + 'static)`
...
LL | let t: &dyn Trait = &get_function()();
- | ^^^^^^^^^^^^^^--
- | |
- | call expression requires function
+ | ^^^^^^^^^^^^^^ this trait object returns an unsized value `(dyn Trait + 'static)`, so it cannot be called
error: aborting due to previous error
help: remove the extra argument
|
LL | fn main() { foo(5) }
- | ~~~~~~
+ | ~~~
error: aborting due to previous error
LL | assert_eq!(Foo::Bar, i);
| ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
- = help: the trait `Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}`
+ = help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}`
= help: the following other types implement trait `Debug`:
extern "C" fn() -> Ret
extern "C" fn(A, B) -> Ret
LL | assert_eq!(Foo::Bar, i);
| ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
- = help: the trait `Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}`
+ = help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}`
= help: the following other types implement trait `Debug`:
extern "C" fn() -> Ret
extern "C" fn(A, B) -> Ret
LL | assert_eq!(a, 0);
| ^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
- = help: the trait `Debug` is not implemented for `fn() -> i32 {a}`
+ = help: the trait `Debug` is not implemented for fn item `fn() -> i32 {a}`
= help: use parentheses to call the function: `a()`
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
--- /dev/null
+struct Argument;
+struct Return;
+
+fn function(_: Argument) -> Return { todo!() }
+
+trait Trait {}
+impl Trait for fn(Argument) -> Return {}
+
+fn takes(_: impl Trait) {}
+
+fn main() {
+ takes(function);
+ //~^ ERROR the trait bound
+ takes(|_: Argument| -> Return { todo!() });
+ //~^ ERROR the trait bound
+}
--- /dev/null
+error[E0277]: the trait bound `fn(Argument) -> Return {function}: Trait` is not satisfied
+ --> $DIR/issue-99875.rs:12:11
+ |
+LL | takes(function);
+ | ----- ^^^^^^^^ the trait `Trait` is not implemented for fn item `fn(Argument) -> Return {function}`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
+note: required by a bound in `takes`
+ --> $DIR/issue-99875.rs:9:18
+ |
+LL | fn takes(_: impl Trait) {}
+ | ^^^^^ required by this bound in `takes`
+
+error[E0277]: the trait bound `[closure@$DIR/issue-99875.rs:14:11: 14:34]: Trait` is not satisfied
+ --> $DIR/issue-99875.rs:14:11
+ |
+LL | takes(|_: Argument| -> Return { todo!() });
+ | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for closure `[closure@$DIR/issue-99875.rs:14:11: 14:34]`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
+note: required by a bound in `takes`
+ --> $DIR/issue-99875.rs:9:18
+ |
+LL | fn takes(_: impl Trait) {}
+ | ^^^^^ required by this bound in `takes`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
fn main() {
let _ = Iterator::next(&mut ());
//~^ ERROR `()` is not an iterator
+ //~| ERROR `()` is not an iterator
+ //~| ERROR `()` is not an iterator
for _ in false {}
//~^ ERROR `bool` is not an iterator
let _ = Iterator::next(&mut ());
//~^ ERROR `()` is not an iterator
+ //~| ERROR `()` is not an iterator
other()
}
let _ = Iterator::next(&mut ());
//~^ ERROR `()` is not an iterator
+ //~| ERROR `()` is not an iterator
+ //~| ERROR `()` is not an iterator
let _ = Iterator::next(&mut ());
//~^ ERROR `()` is not an iterator
+ //~| ERROR `()` is not an iterator
for _ in false {}
//~^ ERROR `bool` is not an iterator
|
= help: the trait `Iterator` is not implemented for `()`
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:2:13
+ |
+LL | let _ = Iterator::next(&mut ());
+ | ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
error[E0277]: `bool` is not an iterator
- --> $DIR/issue-28098.rs:5:14
+ --> $DIR/issue-28098.rs:7:14
|
LL | for _ in false {}
| ^^^^^ `bool` is not an iterator
= note: required for `bool` to implement `IntoIterator`
error[E0277]: `()` is not an iterator
- --> $DIR/issue-28098.rs:8:28
+ --> $DIR/issue-28098.rs:10:28
|
LL | let _ = Iterator::next(&mut ());
| -------------- ^^^^^^^ `()` is not an iterator
= help: the trait `Iterator` is not implemented for `()`
error[E0277]: `()` is not an iterator
- --> $DIR/issue-28098.rs:17:28
+ --> $DIR/issue-28098.rs:10:13
+ |
+LL | let _ = Iterator::next(&mut ());
+ | ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:2:13
+ |
+LL | let _ = Iterator::next(&mut ());
+ | ^^^^^^^^^^^^^^ `()` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:20:28
|
LL | let _ = Iterator::next(&mut ());
| -------------- ^^^^^^^ `()` is not an iterator
= help: the trait `Iterator` is not implemented for `()`
error[E0277]: `()` is not an iterator
- --> $DIR/issue-28098.rs:20:28
+ --> $DIR/issue-28098.rs:20:13
+ |
+LL | let _ = Iterator::next(&mut ());
+ | ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:25:28
|
LL | let _ = Iterator::next(&mut ());
| -------------- ^^^^^^^ `()` is not an iterator
|
= help: the trait `Iterator` is not implemented for `()`
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:25:13
+ |
+LL | let _ = Iterator::next(&mut ());
+ | ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
error[E0277]: `bool` is not an iterator
- --> $DIR/issue-28098.rs:23:14
+ --> $DIR/issue-28098.rs:29:14
|
LL | for _ in false {}
| ^^^^^ `bool` is not an iterator
= help: the trait `Iterator` is not implemented for `bool`
= note: required for `bool` to implement `IntoIterator`
-error: aborting due to 6 previous errors
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:20:13
+ |
+LL | let _ = Iterator::next(&mut ());
+ | ^^^^^^^^^^^^^^ `()` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
+error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// run-pass
+// edition:2021
+// check-run-results
+//
+// Drop order tests for let else
+//
+// Mostly this ensures two things:
+// 1. That let and let else temporary drop order is the same.
+// This is a specific design request: https://github.com/rust-lang/rust/pull/93628#issuecomment-1047140316
+// 2. That the else block truly only runs after the
+// temporaries have dropped.
+//
+// We also print some nice tables for an overview by humans.
+// Changes in those tables are considered breakages, but the
+// important properties 1 and 2 are also enforced by the code.
+// This is important as it's easy to update the stdout file
+// with a --bless and miss the impact of that change.
+
+#![feature(let_else)]
+#![allow(irrefutable_let_patterns)]
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+#[derive(Clone)]
+struct DropAccountant(Rc<RefCell<Vec<Vec<String>>>>);
+
+impl DropAccountant {
+ fn new() -> Self {
+ Self(Default::default())
+ }
+ fn build_droppy(&self, v: u32) -> Droppy<u32> {
+ Droppy(self.clone(), v)
+ }
+ fn build_droppy_enum_none(&self, _v: u32) -> ((), DroppyEnum<u32>) {
+ ((), DroppyEnum::None(self.clone()))
+ }
+ fn new_list(&self, s: impl ToString) {
+ self.0.borrow_mut().push(vec![s.to_string()]);
+ }
+ fn push(&self, s: impl ToString) {
+ let s = s.to_string();
+ let mut accounts = self.0.borrow_mut();
+ accounts.last_mut().unwrap().push(s);
+ }
+ fn print_table(&self) {
+ println!();
+
+ let accounts = self.0.borrow();
+ let before_last = &accounts[accounts.len() - 2];
+ let last = &accounts[accounts.len() - 1];
+ let before_last = get_comma_list(before_last);
+ let last = get_comma_list(last);
+ const LINES: &[&str] = &[
+ "vanilla",
+ "&",
+ "&mut",
+ "move",
+ "fn(this)",
+ "tuple",
+ "array",
+ "ref &",
+ "ref mut &mut",
+ ];
+ let max_len = LINES.iter().map(|v| v.len()).max().unwrap();
+ let max_len_before = before_last.iter().map(|v| v.len()).max().unwrap();
+ let max_len_last = last.iter().map(|v| v.len()).max().unwrap();
+
+ println!(
+ "| {: <max_len$} | {: <max_len_before$} | {: <max_len_last$} |",
+ "construct", before_last[0], last[0]
+ );
+ println!("| {:-<max_len$} | {:-<max_len_before$} | {:-<max_len_last$} |", "", "", "");
+
+ for ((l, l_before), l_last) in
+ LINES.iter().zip(before_last[1..].iter()).zip(last[1..].iter())
+ {
+ println!(
+ "| {: <max_len$} | {: <max_len_before$} | {: <max_len_last$} |",
+ l, l_before, l_last,
+ );
+ }
+ }
+ #[track_caller]
+ fn assert_all_equal_to(&self, st: &str) {
+ let accounts = self.0.borrow();
+ let last = &accounts[accounts.len() - 1];
+ let last = get_comma_list(last);
+ for line in last[1..].iter() {
+ assert_eq!(line.trim(), st.trim());
+ }
+ }
+ #[track_caller]
+ fn assert_equality_last_two_lists(&self) {
+ let accounts = self.0.borrow();
+ let last = &accounts[accounts.len() - 1];
+ let before_last = &accounts[accounts.len() - 2];
+ for (l, b) in last[1..].iter().zip(before_last[1..].iter()) {
+ if !(l == b || l == "n/a" || b == "n/a") {
+ panic!("not equal: '{last:?}' != '{before_last:?}'");
+ }
+ }
+ }
+}
+
+fn get_comma_list(sl: &[String]) -> Vec<String> {
+ std::iter::once(sl[0].clone())
+ .chain(sl[1..].chunks(2).map(|c| c.join(",")))
+ .collect::<Vec<String>>()
+}
+
+struct Droppy<T>(DropAccountant, T);
+
+impl<T> Drop for Droppy<T> {
+ fn drop(&mut self) {
+ self.0.push("drop");
+ }
+}
+
+#[allow(dead_code)]
+enum DroppyEnum<T> {
+ Some(DropAccountant, T),
+ None(DropAccountant),
+}
+
+impl<T> Drop for DroppyEnum<T> {
+ fn drop(&mut self) {
+ match self {
+ DroppyEnum::Some(acc, _inner) => acc,
+ DroppyEnum::None(acc) => acc,
+ }
+ .push("drop");
+ }
+}
+
+macro_rules! nestings_with {
+ ($construct:ident, $binding:pat, $exp:expr) => {
+ // vanilla:
+ $construct!($binding, $exp.1);
+
+ // &:
+ $construct!(&$binding, &$exp.1);
+
+ // &mut:
+ $construct!(&mut $binding, &mut ($exp.1));
+
+ {
+ // move:
+ let w = $exp;
+ $construct!(
+ $binding,
+ {
+ let w = w;
+ w
+ }
+ .1
+ );
+ }
+
+ // fn(this):
+ $construct!($binding, std::convert::identity($exp).1);
+ };
+}
+
+macro_rules! nestings {
+ ($construct:ident, $binding:pat, $exp:expr) => {
+ nestings_with!($construct, $binding, $exp);
+
+ // tuple:
+ $construct!(($binding, 77), ($exp.1, 77));
+
+ // array:
+ $construct!([$binding], [$exp.1]);
+ };
+}
+
+macro_rules! let_else {
+ ($acc:expr, $v:expr, $binding:pat, $build:ident) => {
+ let acc = $acc;
+ let v = $v;
+
+ macro_rules! let_else_construct {
+ ($arg:pat, $exp:expr) => {
+ loop {
+ let $arg = $exp else {
+ acc.push("else");
+ break;
+ };
+ acc.push("body");
+ break;
+ }
+ };
+ }
+ nestings!(let_else_construct, $binding, acc.$build(v));
+ // ref &:
+ let_else_construct!($binding, &acc.$build(v).1);
+
+ // ref mut &mut:
+ let_else_construct!($binding, &mut acc.$build(v).1);
+ };
+}
+
+macro_rules! let_ {
+ ($acc:expr, $binding:tt) => {
+ let acc = $acc;
+
+ macro_rules! let_construct {
+ ($arg:pat, $exp:expr) => {{
+ let $arg = $exp;
+ acc.push("body");
+ }};
+ }
+ let v = 0;
+ {
+ nestings_with!(let_construct, $binding, acc.build_droppy(v));
+ }
+ acc.push("n/a");
+ acc.push("n/a");
+ acc.push("n/a");
+ acc.push("n/a");
+
+ // ref &:
+ let_construct!($binding, &acc.build_droppy(v).1);
+
+ // ref mut &mut:
+ let_construct!($binding, &mut acc.build_droppy(v).1);
+ };
+}
+
+fn main() {
+ let acc = DropAccountant::new();
+
+ println!(" --- matching cases ---");
+
+ // Ensure that let and let else have the same behaviour
+ acc.new_list("let _");
+ let_!(&acc, _);
+ acc.new_list("let else _");
+ let_else!(&acc, 0, _, build_droppy);
+ acc.assert_equality_last_two_lists();
+ acc.print_table();
+
+ // Ensure that let and let else have the same behaviour
+ acc.new_list("let _v");
+ let_!(&acc, _v);
+ acc.new_list("let else _v");
+ let_else!(&acc, 0, _v, build_droppy);
+ acc.assert_equality_last_two_lists();
+ acc.print_table();
+
+ println!();
+
+ println!(" --- mismatching cases ---");
+
+ acc.new_list("let else _ mismatch");
+ let_else!(&acc, 1, DroppyEnum::Some(_, _), build_droppy_enum_none);
+ acc.new_list("let else _v mismatch");
+ let_else!(&acc, 1, DroppyEnum::Some(_, _v), build_droppy_enum_none);
+ acc.print_table();
+ // This ensures that we always drop before visiting the else case
+ acc.assert_all_equal_to("drop,else");
+
+ acc.new_list("let else 0 mismatch");
+ let_else!(&acc, 1, 0, build_droppy);
+ acc.new_list("let else 0 mismatch");
+ let_else!(&acc, 1, 0, build_droppy);
+ acc.print_table();
+ // This ensures that we always drop before visiting the else case
+ acc.assert_all_equal_to("drop,else");
+}
--- /dev/null
+ --- matching cases ---
+
+| construct | let _ | let else _ |
+| ------------ | --------- | ---------- |
+| vanilla | drop,body | drop,body |
+| & | body,drop | body,drop |
+| &mut | body,drop | body,drop |
+| move | drop,body | drop,body |
+| fn(this) | drop,body | drop,body |
+| tuple | n/a,n/a | drop,body |
+| array | n/a,n/a | drop,body |
+| ref & | body,drop | body,drop |
+| ref mut &mut | body,drop | body,drop |
+
+| construct | let _v | let else _v |
+| ------------ | --------- | ----------- |
+| vanilla | drop,body | drop,body |
+| & | body,drop | body,drop |
+| &mut | body,drop | body,drop |
+| move | drop,body | drop,body |
+| fn(this) | drop,body | drop,body |
+| tuple | n/a,n/a | drop,body |
+| array | n/a,n/a | drop,body |
+| ref & | body,drop | body,drop |
+| ref mut &mut | body,drop | body,drop |
+
+ --- mismatching cases ---
+
+| construct | let else _ mismatch | let else _v mismatch |
+| ------------ | ------------------- | -------------------- |
+| vanilla | drop,else | drop,else |
+| & | drop,else | drop,else |
+| &mut | drop,else | drop,else |
+| move | drop,else | drop,else |
+| fn(this) | drop,else | drop,else |
+| tuple | drop,else | drop,else |
+| array | drop,else | drop,else |
+| ref & | drop,else | drop,else |
+| ref mut &mut | drop,else | drop,else |
+
+| construct | let else 0 mismatch | let else 0 mismatch |
+| ------------ | ------------------- | ------------------- |
+| vanilla | drop,else | drop,else |
+| & | drop,else | drop,else |
+| &mut | drop,else | drop,else |
+| move | drop,else | drop,else |
+| fn(this) | drop,else | drop,else |
+| tuple | drop,else | drop,else |
+| array | drop,else | drop,else |
+| ref & | drop,else | drop,else |
+| ref mut &mut | drop,else | drop,else |
help: provide the argument
|
LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter(/* &u8 */) }
- | ~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~
error[E0308]: mismatched types
--> $DIR/issue-26638.rs:5:47
--- /dev/null
+// check-pass
+// edition:2021
+#![deny(rust_2021_compatibility)]
+
+pub struct Warns {
+ // `Arc` has significant drop
+ _significant_drop: std::sync::Arc<()>,
+ field: String,
+}
+
+pub fn test(w: Warns) {
+ _ = || drop(w.field);
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+#![warn(let_underscore_drop)]
+
+struct NontrivialDrop;
+
+impl Drop for NontrivialDrop {
+ fn drop(&mut self) {
+ println!("Dropping!");
+ }
+}
+
+fn main() {
+ let _ = NontrivialDrop; //~WARNING non-binding let on a type that implements `Drop`
+}
--- /dev/null
+warning: non-binding let on a type that implements `Drop`
+ --> $DIR/let_underscore_drop.rs:13:5
+ |
+LL | let _ = NontrivialDrop;
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/let_underscore_drop.rs:2:9
+ |
+LL | #![warn(let_underscore_drop)]
+ | ^^^^^^^^^^^^^^^^^^^
+help: consider binding to an unused variable to avoid immediately dropping the value
+ |
+LL | let _unused = NontrivialDrop;
+ | ~~~~~~~
+help: consider immediately dropping the value
+ |
+LL | drop(NontrivialDrop);
+ | ~~~~~ +
+
+warning: 1 warning emitted
+
--- /dev/null
+// check-fail
+use std::sync::{Arc, Mutex};
+
+fn main() {
+ let data = Arc::new(Mutex::new(0));
+ let _ = data.lock().unwrap(); //~ERROR non-binding let on a synchronization lock
+}
--- /dev/null
+error: non-binding let on a synchronization lock
+ --> $DIR/let_underscore_lock.rs:6:9
+ |
+LL | let _ = data.lock().unwrap();
+ | ^ ^^^^^^^^^^^^^^^^^^^^ this binding will immediately drop the value assigned to it
+ | |
+ | this lock is not assigned to a binding and is immediately dropped
+ |
+ = note: `#[deny(let_underscore_lock)]` on by default
+help: consider binding to an unused variable to avoid immediately dropping the value
+ |
+LL | let _unused = data.lock().unwrap();
+ | ~~~~~~~
+help: consider immediately dropping the value
+ |
+LL | drop(data.lock().unwrap());
+ | ~~~~~ +
+
+error: aborting due to previous error
+
help: remove the extra argument
|
LL | x.zero()
- | ~~~~~~
+ | ~~
error[E0061]: this function takes 1 argument but 0 arguments were supplied
--> $DIR/method-call-err-msg.rs:14:7
help: provide the argument
|
LL | .one(/* isize */)
- | ~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~
error[E0061]: this function takes 2 arguments but 1 argument was supplied
--> $DIR/method-call-err-msg.rs:15:7
help: provide the argument
|
LL | .two(0, /* isize */);
- | ~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~
error[E0599]: `Foo` is not an iterator
--> $DIR/method-call-err-msg.rs:19:7
help: provide the arguments
|
LL | y.three::<usize>(/* usize */, /* usize */, /* usize */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 5 previous errors
--- /dev/null
+// check-pass
+pub trait Backend {
+ type DescriptorSetLayout;
+}
+
+pub struct Back;
+
+impl Backend for Back {
+ type DescriptorSetLayout = u32;
+}
+
+pub struct HalSetLayouts {
+ vertex_layout: <Back as Backend>::DescriptorSetLayout,
+}
+
+impl HalSetLayouts {
+ pub fn iter<DSL>(self) -> DSL
+ where
+ Back: Backend<DescriptorSetLayout = DSL>,
+ {
+ self.vertex_layout
+ }
+}
+
+fn main() {}
help: provide the argument
|
LL | let ans = s(/* isize */);
- | ~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~
error[E0057]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/overloaded-calls-bad.rs:31:15
help: remove the extra argument
|
LL | let ans = s(/* isize */);
- | ~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~
error: aborting due to 3 previous errors
--- /dev/null
+#[allow(dead_code)]
+pub struct Dummy;
--- /dev/null
+mod lib;
+//~^ WARN found module declaration for lib.rs
+//~| ERROR file not found for module `lib`
+mod main;
+//~^ WARN found module declaration for main.rs
+//~| ERROR file not found for module `main`
+
+fn main() {}
--- /dev/null
+error[E0583]: file not found for module `lib`
+ --> $DIR/special_module_name.rs:1:1
+ |
+LL | mod lib;
+ | ^^^^^^^^
+ |
+ = help: to create the module `lib`, create file "$DIR/lib.rs" or "$DIR/lib/mod.rs"
+
+error[E0583]: file not found for module `main`
+ --> $DIR/special_module_name.rs:4:1
+ |
+LL | mod main;
+ | ^^^^^^^^^
+ |
+ = help: to create the module `main`, create file "$DIR/main.rs" or "$DIR/main/mod.rs"
+
+warning: found module declaration for lib.rs
+ --> $DIR/special_module_name.rs:1:1
+ |
+LL | mod lib;
+ | ^^^^^^^^
+ |
+ = note: `#[warn(special_module_name)]` on by default
+ = note: lib.rs is the root of this crate's library target
+ = help: to refer to it from other targets, use the library's name as the path
+
+warning: found module declaration for main.rs
+ --> $DIR/special_module_name.rs:4:1
+ |
+LL | mod main;
+ | ^^^^^^^^^
+ |
+ = note: a binary crate cannot be used as library
+
+error: aborting due to 2 previous errors; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0583`.
--- /dev/null
+// run-pass
+
+#[path = "auxiliary/dummy_lib.rs"]
+mod lib;
+
+#[path = "auxiliary/dummy_lib.rs"]
+mod main;
+
+fn main() {}
--> $DIR/namespace-mix.rs:56:11
|
LL | check(m3::TS);
- | ----- ^^^^^^ the trait `Impossible` is not implemented for `fn() -> c::TS {c::TS}`
+ | ----- ^^^^^^ the trait `Impossible` is not implemented for fn item `fn() -> c::TS {c::TS}`
| |
| required by a bound introduced by this call
|
--> $DIR/namespace-mix.rs:62:11
|
LL | check(xm3::TS);
- | ----- ^^^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::TS {namespace_mix::c::TS}`
+ | ----- ^^^^^^^ the trait `Impossible` is not implemented for fn item `fn() -> namespace_mix::c::TS {namespace_mix::c::TS}`
| |
| required by a bound introduced by this call
|
--> $DIR/namespace-mix.rs:122:11
|
LL | check(m9::TV);
- | ----- ^^^^^^ the trait `Impossible` is not implemented for `fn() -> c::E {c::E::TV}`
+ | ----- ^^^^^^ the trait `Impossible` is not implemented for fn item `fn() -> c::E {c::E::TV}`
| |
| required by a bound introduced by this call
|
--> $DIR/namespace-mix.rs:128:11
|
LL | check(xm9::TV);
- | ----- ^^^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::E {namespace_mix::xm7::TV}`
+ | ----- ^^^^^^^ the trait `Impossible` is not implemented for fn item `fn() -> namespace_mix::c::E {namespace_mix::xm7::TV}`
| |
| required by a bound introduced by this call
|
help: provide the argument
|
LL | foo(1, 2, 3, /* isize */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 6 arguments but 3 arguments were supplied
--> $DIR/not-enough-arguments.rs:29:3
help: provide the arguments
|
LL | bar(1, 2, 3, /* i32 */, /* i32 */, /* i32 */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors
#![feature(rustc_attrs)]
#[rustc_object_lifetime_default]
-struct A<T>(T); //~ ERROR BaseDefault
+struct A<
+ T, //~ ERROR BaseDefault
+>(T);
#[rustc_object_lifetime_default]
-struct B<'a,T>(&'a (), T); //~ ERROR BaseDefault
+struct B<
+ 'a,
+ T, //~ ERROR BaseDefault
+>(&'a (), T);
#[rustc_object_lifetime_default]
-struct C<'a,T:'a>(&'a T); //~ ERROR 'a
+struct C<
+ 'a,
+ T: 'a, //~ ERROR 'a
+>(&'a T);
#[rustc_object_lifetime_default]
-struct D<'a,'b,T:'a+'b>(&'a T, &'b T); //~ ERROR Ambiguous
+struct D<
+ 'a,
+ 'b,
+ T: 'a + 'b, //~ ERROR Ambiguous
+>(&'a T, &'b T);
#[rustc_object_lifetime_default]
-struct E<'a,'b:'a,T:'b>(&'a T, &'b T); //~ ERROR 'b
+struct E<
+ 'a,
+ 'b: 'a,
+ T: 'b, //~ ERROR 'b
+>(&'a T, &'b T);
#[rustc_object_lifetime_default]
-struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); //~ ERROR 'a,'b
+struct F<
+ 'a,
+ 'b,
+ T: 'a, //~ ERROR 'a
+ U: 'b, //~ ERROR 'b
+>(&'a T, &'b U);
#[rustc_object_lifetime_default]
-struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); //~ ERROR 'a,Ambiguous
-
-fn main() { }
+struct G<
+ 'a,
+ 'b,
+ T: 'a, //~ ERROR 'a
+ U: 'a + 'b, //~ ERROR Ambiguous
+>(&'a T, &'b U);
+
+fn main() {}
error: BaseDefault
- --> $DIR/object-lifetime-default.rs:4:1
+ --> $DIR/object-lifetime-default.rs:5:5
|
-LL | struct A<T>(T);
- | ^^^^^^^^^^^^^^^
+LL | T,
+ | ^
error: BaseDefault
- --> $DIR/object-lifetime-default.rs:7:1
+ --> $DIR/object-lifetime-default.rs:11:5
|
-LL | struct B<'a,T>(&'a (), T);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | T,
+ | ^
error: 'a
- --> $DIR/object-lifetime-default.rs:10:1
+ --> $DIR/object-lifetime-default.rs:17:5
|
-LL | struct C<'a,T:'a>(&'a T);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | T: 'a,
+ | ^
error: Ambiguous
- --> $DIR/object-lifetime-default.rs:13:1
+ --> $DIR/object-lifetime-default.rs:24:5
|
-LL | struct D<'a,'b,T:'a+'b>(&'a T, &'b T);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | T: 'a + 'b,
+ | ^
error: 'b
- --> $DIR/object-lifetime-default.rs:16:1
+ --> $DIR/object-lifetime-default.rs:31:5
|
-LL | struct E<'a,'b:'a,T:'b>(&'a T, &'b T);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | T: 'b,
+ | ^
-error: 'a,'b
- --> $DIR/object-lifetime-default.rs:19:1
+error: 'a
+ --> $DIR/object-lifetime-default.rs:38:5
+ |
+LL | T: 'a,
+ | ^
+
+error: 'b
+ --> $DIR/object-lifetime-default.rs:39:5
|
-LL | struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | U: 'b,
+ | ^
-error: 'a,Ambiguous
- --> $DIR/object-lifetime-default.rs:22:1
+error: 'a
+ --> $DIR/object-lifetime-default.rs:46:5
+ |
+LL | T: 'a,
+ | ^
+
+error: Ambiguous
+ --> $DIR/object-lifetime-default.rs:47:5
|
-LL | struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | U: 'a + 'b,
+ | ^
-error: aborting due to 7 previous errors
+error: aborting due to 9 previous errors
+++ /dev/null
-// Test scope annotations from `enclosing_scope` parameter
-
-#![feature(rustc_attrs)]
-
-#[rustc_on_unimplemented(enclosing_scope="in this scope")]
-trait Trait{}
-
-struct Foo;
-
-fn f<T: Trait>(x: T) {}
-
-fn main() {
- let x = || {
- f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
- let y = || {
- f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
- };
- };
-
- {
- {
- f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
- }
- }
-
- f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
-}
+++ /dev/null
-error[E0277]: the trait bound `Foo: Trait` is not satisfied
- --> $DIR/enclosing-scope.rs:14:11
- |
-LL | let x = || {
- | _____________-
-LL | | f(Foo{});
- | | - ^^^^^ the trait `Trait` is not implemented for `Foo`
- | | |
- | | required by a bound introduced by this call
-LL | | let y = || {
-LL | | f(Foo{});
-LL | | };
-LL | | };
- | |_____- in this scope
- |
-note: required by a bound in `f`
- --> $DIR/enclosing-scope.rs:10:9
- |
-LL | fn f<T: Trait>(x: T) {}
- | ^^^^^ required by this bound in `f`
-
-error[E0277]: the trait bound `Foo: Trait` is not satisfied
- --> $DIR/enclosing-scope.rs:16:15
- |
-LL | let y = || {
- | _________________-
-LL | | f(Foo{});
- | | - ^^^^^ the trait `Trait` is not implemented for `Foo`
- | | |
- | | required by a bound introduced by this call
-LL | | };
- | |_________- in this scope
- |
-note: required by a bound in `f`
- --> $DIR/enclosing-scope.rs:10:9
- |
-LL | fn f<T: Trait>(x: T) {}
- | ^^^^^ required by this bound in `f`
-
-error[E0277]: the trait bound `Foo: Trait` is not satisfied
- --> $DIR/enclosing-scope.rs:22:15
- |
-LL | / fn main() {
-LL | | let x = || {
-LL | | f(Foo{});
-LL | | let y = || {
-... |
-LL | | f(Foo{});
- | | - ^^^^^ the trait `Trait` is not implemented for `Foo`
- | | |
- | | required by a bound introduced by this call
-... |
-LL | | f(Foo{});
-LL | | }
- | |_- in this scope
- |
-note: required by a bound in `f`
- --> $DIR/enclosing-scope.rs:10:9
- |
-LL | fn f<T: Trait>(x: T) {}
- | ^^^^^ required by this bound in `f`
-
-error[E0277]: the trait bound `Foo: Trait` is not satisfied
- --> $DIR/enclosing-scope.rs:26:7
- |
-LL | / fn main() {
-LL | | let x = || {
-LL | | f(Foo{});
-LL | | let y = || {
-... |
-LL | | f(Foo{});
- | | - ^^^^^ the trait `Trait` is not implemented for `Foo`
- | | |
- | | required by a bound introduced by this call
-LL | | }
- | |_- in this scope
- |
-note: required by a bound in `f`
- --> $DIR/enclosing-scope.rs:10:9
- |
-LL | fn f<T: Trait>(x: T) {}
- | ^^^^^ required by this bound in `f`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
fn main() {
Index::index(&[] as &[i32], 2u32);
//~^ ERROR E0277
+ //~| ERROR E0277
+ //~| ERROR E0277
Index::index(&[] as &[i32], Foo(2u32));
//~^ ERROR E0277
+ //~| ERROR E0277
+ //~| ERROR E0277
Index::index(&[] as &[i32], Bar(2u32));
//~^ ERROR E0277
+ //~| ERROR E0277
+ //~| ERROR E0277
}
<[i32] as Index<Bar<usize>>>
<[i32] as Index<Foo<usize>>>
+error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
+ --> $DIR/multiple-impls.rs:33:5
+ |
+LL | Index::index(&[] as &[i32], 2u32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait message
+ |
+ = help: the trait `Index<u32>` is not implemented for `[i32]`
+ = help: the following other types implement trait `Index<Idx>`:
+ <[i32] as Index<Bar<usize>>>
+ <[i32] as Index<Foo<usize>>>
+
error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
- --> $DIR/multiple-impls.rs:35:33
+ --> $DIR/multiple-impls.rs:37:33
|
LL | Index::index(&[] as &[i32], Foo(2u32));
| ------------ ^^^^^^^^^ on impl for Foo
<[i32] as Index<Bar<usize>>>
<[i32] as Index<Foo<usize>>>
+error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
+ --> $DIR/multiple-impls.rs:37:5
+ |
+LL | Index::index(&[] as &[i32], Foo(2u32));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Foo
+ |
+ = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]`
+ = help: the following other types implement trait `Index<Idx>`:
+ <[i32] as Index<Bar<usize>>>
+ <[i32] as Index<Foo<usize>>>
+
error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
- --> $DIR/multiple-impls.rs:37:33
+ --> $DIR/multiple-impls.rs:41:33
|
LL | Index::index(&[] as &[i32], Bar(2u32));
| ------------ ^^^^^^^^^ on impl for Bar
<[i32] as Index<Bar<usize>>>
<[i32] as Index<Foo<usize>>>
-error: aborting due to 3 previous errors
+error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
+ --> $DIR/multiple-impls.rs:41:5
+ |
+LL | Index::index(&[] as &[i32], Bar(2u32));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar
+ |
+ = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]`
+ = help: the following other types implement trait `Index<Idx>`:
+ <[i32] as Index<Bar<usize>>>
+ <[i32] as Index<Foo<usize>>>
+
+error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
+ --> $DIR/multiple-impls.rs:33:5
+ |
+LL | Index::index(&[] as &[i32], 2u32);
+ | ^^^^^^^^^^^^ trait message
+ |
+ = help: the trait `Index<u32>` is not implemented for `[i32]`
+ = help: the following other types implement trait `Index<Idx>`:
+ <[i32] as Index<Bar<usize>>>
+ <[i32] as Index<Foo<usize>>>
+
+error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
+ --> $DIR/multiple-impls.rs:37:5
+ |
+LL | Index::index(&[] as &[i32], Foo(2u32));
+ | ^^^^^^^^^^^^ on impl for Foo
+ |
+ = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]`
+ = help: the following other types implement trait `Index<Idx>`:
+ <[i32] as Index<Bar<usize>>>
+ <[i32] as Index<Foo<usize>>>
+
+error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
+ --> $DIR/multiple-impls.rs:41:5
+ |
+LL | Index::index(&[] as &[i32], Bar(2u32));
+ | ^^^^^^^^^^^^ on impl for Bar
+ |
+ = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]`
+ = help: the following other types implement trait `Index<Idx>`:
+ <[i32] as Index<Bar<usize>>>
+ <[i32] as Index<Foo<usize>>>
+
+error: aborting due to 9 previous errors
For more information about this error, try `rustc --explain E0277`.
fn main() {
Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
//~^ ERROR E0277
+ //~| ERROR E0277
+ //~| ERROR E0277
}
= help: the trait `Index<u32>` is not implemented for `[i32]`
= help: the trait `Index<usize>` is implemented for `[i32]`
-error: aborting due to previous error
+error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
+ --> $DIR/on-impl.rs:22:5
+ |
+LL | Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice
+ |
+ = help: the trait `Index<u32>` is not implemented for `[i32]`
+ = help: the trait `Index<usize>` is implemented for `[i32]`
+
+error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
+ --> $DIR/on-impl.rs:22:5
+ |
+LL | Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
+ | ^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice
+ |
+ = help: the trait `Index<u32>` is not implemented for `[i32]`
+ = help: the trait `Index<usize>` is implemented for `[i32]`
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Test scope annotations from `parent_label` parameter
+
+#![feature(rustc_attrs)]
+
+#[rustc_on_unimplemented(parent_label = "in this scope")]
+trait Trait {}
+
+struct Foo;
+
+fn f<T: Trait>(x: T) {}
+
+fn main() {
+ let x = || {
+ f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
+ let y = || {
+ f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
+ };
+ };
+
+ {
+ {
+ f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
+ }
+ }
+
+ f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `Foo: Trait` is not satisfied
+ --> $DIR/parent-label.rs:14:11
+ |
+LL | let x = || {
+ | -- in this scope
+LL | f(Foo {});
+ | - ^^^^^^ the trait `Trait` is not implemented for `Foo`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `f`
+ --> $DIR/parent-label.rs:10:9
+ |
+LL | fn f<T: Trait>(x: T) {}
+ | ^^^^^ required by this bound in `f`
+
+error[E0277]: the trait bound `Foo: Trait` is not satisfied
+ --> $DIR/parent-label.rs:16:15
+ |
+LL | let y = || {
+ | -- in this scope
+LL | f(Foo {});
+ | - ^^^^^^ the trait `Trait` is not implemented for `Foo`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `f`
+ --> $DIR/parent-label.rs:10:9
+ |
+LL | fn f<T: Trait>(x: T) {}
+ | ^^^^^ required by this bound in `f`
+
+error[E0277]: the trait bound `Foo: Trait` is not satisfied
+ --> $DIR/parent-label.rs:22:15
+ |
+LL | fn main() {
+ | --------- in this scope
+...
+LL | f(Foo {});
+ | - ^^^^^^ the trait `Trait` is not implemented for `Foo`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `f`
+ --> $DIR/parent-label.rs:10:9
+ |
+LL | fn f<T: Trait>(x: T) {}
+ | ^^^^^ required by this bound in `f`
+
+error[E0277]: the trait bound `Foo: Trait` is not satisfied
+ --> $DIR/parent-label.rs:26:7
+ |
+LL | fn main() {
+ | --------- in this scope
+...
+LL | f(Foo {});
+ | - ^^^^^^ the trait `Trait` is not implemented for `Foo`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `f`
+ --> $DIR/parent-label.rs:10:9
+ |
+LL | fn f<T: Trait>(x: T) {}
+ | ^^^^^ required by this bound in `f`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(rustc_attrs)]
+
+#[rustc_access_level] mod outer { //~ ERROR None
+ #[rustc_access_level] pub mod inner { //~ ERROR Some(Exported)
+ #[rustc_access_level]
+ extern "C" { //~ ERROR Some(Exported)
+ #[rustc_access_level] static a: u8; //~ ERROR None
+ #[rustc_access_level] pub fn b(); //~ ERROR Some(Exported)
+ }
+ #[rustc_access_level]
+ pub trait Trait { //~ ERROR Some(Exported)
+ #[rustc_access_level] const A: i32; //~ ERROR Some(Exported)
+ #[rustc_access_level] type B; //~ ERROR Some(Exported)
+ }
+
+ #[rustc_access_level]
+ pub struct Struct { //~ ERROR Some(Exported)
+ #[rustc_access_level] a: u8, //~ ERROR None
+ #[rustc_access_level] pub b: u8, //~ ERROR Some(Exported)
+ }
+
+ #[rustc_access_level]
+ pub union Union { //~ ERROR Some(Exported)
+ #[rustc_access_level] a: u8, //~ ERROR None
+ #[rustc_access_level] pub b: u8, //~ ERROR Some(Exported)
+ }
+
+ #[rustc_access_level]
+ pub enum Enum { //~ ERROR Some(Exported)
+ #[rustc_access_level] A( //~ ERROR Some(Exported)
+ #[rustc_access_level] Struct, //~ ERROR Some(Exported)
+ #[rustc_access_level] Union, //~ ERROR Some(Exported)
+ ),
+ }
+ }
+
+ #[rustc_access_level] macro_rules! none_macro { //~ ERROR None
+ () => {};
+ }
+
+ #[macro_export]
+ #[rustc_access_level] macro_rules! public_macro { //~ ERROR Some(Public)
+ () => {};
+ }
+}
+
+pub use outer::inner;
+
+fn main() {}
--- /dev/null
+error: None
+ --> $DIR/access_levels.rs:3:23
+ |
+LL | #[rustc_access_level] mod outer {
+ | ^^^^^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:4:27
+ |
+LL | #[rustc_access_level] pub mod inner {
+ | ^^^^^^^^^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:6:9
+ |
+LL | / extern "C" {
+LL | | #[rustc_access_level] static a: u8;
+LL | | #[rustc_access_level] pub fn b();
+LL | | }
+ | |_________^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:11:9
+ |
+LL | pub trait Trait {
+ | ^^^^^^^^^^^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:17:9
+ |
+LL | pub struct Struct {
+ | ^^^^^^^^^^^^^^^^^
+
+error: None
+ --> $DIR/access_levels.rs:18:35
+ |
+LL | #[rustc_access_level] a: u8,
+ | ^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:19:35
+ |
+LL | #[rustc_access_level] pub b: u8,
+ | ^^^^^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:23:9
+ |
+LL | pub union Union {
+ | ^^^^^^^^^^^^^^^
+
+error: None
+ --> $DIR/access_levels.rs:24:35
+ |
+LL | #[rustc_access_level] a: u8,
+ | ^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:25:35
+ |
+LL | #[rustc_access_level] pub b: u8,
+ | ^^^^^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:29:9
+ |
+LL | pub enum Enum {
+ | ^^^^^^^^^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:30:35
+ |
+LL | #[rustc_access_level] A(
+ | ^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:31:39
+ |
+LL | #[rustc_access_level] Struct,
+ | ^^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:32:39
+ |
+LL | #[rustc_access_level] Union,
+ | ^^^^^
+
+error: None
+ --> $DIR/access_levels.rs:37:27
+ |
+LL | #[rustc_access_level] macro_rules! none_macro {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Some(Public)
+ --> $DIR/access_levels.rs:42:27
+ |
+LL | #[rustc_access_level] macro_rules! public_macro {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:12:35
+ |
+LL | #[rustc_access_level] const A: i32;
+ | ^^^^^^^^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:13:35
+ |
+LL | #[rustc_access_level] type B;
+ | ^^^^^^
+
+error: None
+ --> $DIR/access_levels.rs:7:35
+ |
+LL | #[rustc_access_level] static a: u8;
+ | ^^^^^^^^^^^^
+
+error: Some(Exported)
+ --> $DIR/access_levels.rs:8:35
+ |
+LL | #[rustc_access_level] pub fn b();
+ | ^^^^^^^^^^
+
+error: aborting due to 20 previous errors
+
pub fn expand_expr_is(input: TokenStream) -> TokenStream {
let mut iter = input.into_iter();
let mut expected_tts = Vec::new();
- loop {
+ let comma = loop {
match iter.next() {
- Some(TokenTree::Punct(ref p)) if p.as_char() == ',' => break,
+ Some(TokenTree::Punct(p)) if p.as_char() == ',' => break p,
Some(tt) => expected_tts.push(tt),
None => panic!("expected comma"),
}
- }
+ };
+
+ // Make sure that `Ident` and `Literal` objects from this proc-macro's
+ // environment are not invalidated when `expand_expr` recursively invokes
+ // another macro by taking a local copy, and checking it after the fact.
+ let pre_expand_span = comma.span();
+ let pre_expand_ident = Ident::new("ident", comma.span());
+ let pre_expand_literal = Literal::string("literal");
+ let pre_expand_call_site = Span::call_site();
let expected = expected_tts.into_iter().collect::<TokenStream>();
let expanded = iter.collect::<TokenStream>().expand_expr().expect("expand_expr failed");
// Also compare the raw tts to make sure they line up.
assert_ts_eq(&expected, &expanded);
+ assert!(comma.span().eq(&pre_expand_span), "pre-expansion span is still equal");
+ assert_eq!(pre_expand_ident.to_string(), "ident", "pre-expansion identifier is still valid");
+ assert_eq!(
+ pre_expand_literal.to_string(),
+ "\"literal\"",
+ "pre-expansion literal is still valid"
+ );
+ assert!(Span::call_site().eq(&pre_expand_call_site), "pre-expansion call-site is still equal");
+
TokenStream::new()
}
| |_call the function in a closure: `|| unsafe { /* code */ }`
| required by a bound introduced by this call
|
- = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
+ = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for fn item `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `ProcMacro::custom_derive`
--> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL
help: remove the extra argument
|
LL | std::mem::size_of();
- | ~~~~~~~~~~~~~~~~~~~
+ | ~~
error: aborting due to 3 previous errors
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/disallowed-positions.rs:132:19
|
-LL | / fn nested_within_if_expr() {
-LL | | if &let 0 = 0 {}
-LL | |
-LL | |
-... |
-LL | | if (let 0 = 0)? {}
- | | ^ cannot use the `?` operator in a function that returns `()`
-... |
-LL | |
-LL | | }
- | |_- this function should return `Result` or `Option` to accept `?`
+LL | fn nested_within_if_expr() {
+ | -------------------------- this function should return `Result` or `Option` to accept `?`
+...
+LL | if (let 0 = 0)? {}
+ | ^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `FromResidual<_>` is not implemented for `()`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/disallowed-positions.rs:224:22
|
-LL | / fn nested_within_while_expr() {
-LL | | while &let 0 = 0 {}
-LL | |
-LL | |
-... |
-LL | | while (let 0 = 0)? {}
- | | ^ cannot use the `?` operator in a function that returns `()`
-... |
-LL | |
-LL | | }
- | |_- this function should return `Result` or `Option` to accept `?`
+LL | fn nested_within_while_expr() {
+ | ----------------------------- this function should return `Result` or `Option` to accept `?`
+...
+LL | while (let 0 = 0)? {}
+ | ^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `FromResidual<_>` is not implemented for `()`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/disallowed-positions.rs:325:16
|
-LL | / fn outside_if_and_while_expr() {
-LL | | &let 0 = 0;
-LL | |
-LL | |
-... |
-LL | | (let 0 = 0)?;
- | | ^ cannot use the `?` operator in a function that returns `()`
-... |
-LL | |
-LL | | }
- | |_- this function should return `Result` or `Option` to accept `?`
+LL | fn outside_if_and_while_expr() {
+ | ------------------------------ this function should return `Result` or `Option` to accept `?`
+...
+LL | (let 0 = 0)?;
+ | ^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `FromResidual<_>` is not implemented for `()`
| |
| required by a bound introduced by this call
|
- = help: the trait `Fn<()>` is not implemented for `fn() {foo}`
+ = help: the trait `Fn<()>` is not implemented for fn item `fn() {foo}`
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
note: required by a bound in `call`
| |
| required by a bound introduced by this call
|
- = help: the trait `FnMut<()>` is not implemented for `fn() {foo}`
+ = help: the trait `FnMut<()>` is not implemented for fn item `fn() {foo}`
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
note: required by a bound in `call_mut`
| |
| required by a bound introduced by this call
|
- = help: the trait `FnOnce<()>` is not implemented for `fn() {foo}`
+ = help: the trait `FnOnce<()>` is not implemented for fn item `fn() {foo}`
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
note: required by a bound in `call_once`
| |
| required by a bound introduced by this call
|
- = help: the trait `Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}`
+ = help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
note: required by a bound in `call`
| |
| required by a bound introduced by this call
|
- = help: the trait `FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}`
+ = help: the trait `FnMut<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
note: required by a bound in `call_mut`
| |
| required by a bound introduced by this call
|
- = help: the trait `FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}`
+ = help: the trait `FnOnce<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
note: required by a bound in `call_once`
help: remove the extra argument
|
LL | foo(Some(42), 2);
- | ~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~
error[E0308]: mismatched types
--> $DIR/issue-34264.rs:8:13
help: remove the extra argument
|
LL | bar(1, 2);
- | ~~~~~~~~~
+ | ~~~~~~
error: aborting due to 6 previous errors
help: provide the argument
|
LL | let _: Result<(), String> = Ok(());
- | ~~~~~~
+ | ~~~~
error[E0061]: this function takes 2 arguments but 0 arguments were supplied
--> $DIR/missing-unit-argument.rs:12:5
help: provide the arguments
|
LL | foo((), ());
- | ~~~~~~~~~~~
+ | ~~~~~~~~
error[E0061]: this function takes 2 arguments but 1 argument was supplied
--> $DIR/missing-unit-argument.rs:13:5
help: provide the argument
|
LL | foo((), ());
- | ~~~~~~~~~~~
+ | ~~~~~~~~
error[E0061]: this function takes 1 argument but 0 arguments were supplied
--> $DIR/missing-unit-argument.rs:14:5
help: provide the argument
|
LL | bar(());
- | ~~~~~~~
+ | ~~~~
error[E0061]: this function takes 1 argument but 0 arguments were supplied
--> $DIR/missing-unit-argument.rs:15:7
help: provide the argument
|
LL | S.baz(());
- | ~~~~~~~
+ | ~~~~
error[E0061]: this function takes 1 argument but 0 arguments were supplied
--> $DIR/missing-unit-argument.rs:16:7
help: provide the argument
|
LL | S.generic::<()>(());
- | ~~~~~~~~~~~~~~~~~
+ | ~~~~
error: aborting due to 6 previous errors
-
-PRE EXPANSION AST STATS
-
-Name Accumulated Size Count Item Size
-----------------------------------------------------------------
-ExprField 48 ( 0.6%) 1 48
-Crate 56 ( 0.7%) 1 56
-Attribute 64 ( 0.8%) 2 32
-- Normal 32 ( 0.4%) 1
-- DocComment 32 ( 0.4%) 1
-GenericArgs 64 ( 0.8%) 1 64
-- AngleBracketed 64 ( 0.8%) 1
-Local 72 ( 0.9%) 1 72
-WherePredicate 72 ( 0.9%) 1 72
-- BoundPredicate 72 ( 0.9%) 1
-Arm 96 ( 1.1%) 2 48
-ForeignItem 96 ( 1.1%) 1 96
-- Fn 96 ( 1.1%) 1
-FieldDef 160 ( 1.9%) 2 80
-Stmt 160 ( 1.9%) 5 32
-- Local 32 ( 0.4%) 1
-- MacCall 32 ( 0.4%) 1
-- Expr 96 ( 1.1%) 3
-Param 160 ( 1.9%) 4 40
-FnDecl 200 ( 2.4%) 5 40
-Variant 240 ( 2.8%) 2 120
-Block 288 ( 3.4%) 6 48
-GenericBound 352 ( 4.2%) 4 88
-- Trait 352 ( 4.2%) 4
-AssocItem 416 ( 4.9%) 4 104
-- TyAlias 208 ( 2.5%) 2
-- Fn 208 ( 2.5%) 2
-GenericParam 520 ( 6.1%) 5 104
-PathSegment 720 ( 8.5%) 30 24
-Expr 832 ( 9.8%) 8 104
-- Path 104 ( 1.2%) 1
-- Match 104 ( 1.2%) 1
-- Struct 104 ( 1.2%) 1
-- Lit 208 ( 2.5%) 2
-- Block 312 ( 3.7%) 3
-Pat 840 ( 9.9%) 7 120
-- Struct 120 ( 1.4%) 1
-- Wild 120 ( 1.4%) 1
-- Ident 600 ( 7.1%) 5
-Ty 1_344 (15.9%) 14 96
-- Rptr 96 ( 1.1%) 1
-- Ptr 96 ( 1.1%) 1
-- ImplicitSelf 192 ( 2.3%) 2
-- Path 960 (11.4%) 10
-Item 1_656 (19.6%) 9 184
-- Trait 184 ( 2.2%) 1
-- Enum 184 ( 2.2%) 1
-- ForeignMod 184 ( 2.2%) 1
-- Impl 184 ( 2.2%) 1
-- Fn 368 ( 4.4%) 2
-- Use 552 ( 6.5%) 3
-----------------------------------------------------------------
-Total 8_456
-
-
-POST EXPANSION AST STATS
-
-Name Accumulated Size Count Item Size
-----------------------------------------------------------------
-ExprField 48 ( 0.5%) 1 48
-Crate 56 ( 0.6%) 1 56
-GenericArgs 64 ( 0.7%) 1 64
-- AngleBracketed 64 ( 0.7%) 1
-Local 72 ( 0.8%) 1 72
-WherePredicate 72 ( 0.8%) 1 72
-- BoundPredicate 72 ( 0.8%) 1
-Arm 96 ( 1.0%) 2 48
-ForeignItem 96 ( 1.0%) 1 96
-- Fn 96 ( 1.0%) 1
-InlineAsm 120 ( 1.3%) 1 120
-Attribute 128 ( 1.4%) 4 32
-- DocComment 32 ( 0.3%) 1
-- Normal 96 ( 1.0%) 3
-FieldDef 160 ( 1.7%) 2 80
-Stmt 160 ( 1.7%) 5 32
-- Local 32 ( 0.3%) 1
-- Semi 32 ( 0.3%) 1
-- Expr 96 ( 1.0%) 3
-Param 160 ( 1.7%) 4 40
-FnDecl 200 ( 2.2%) 5 40
-Variant 240 ( 2.6%) 2 120
-Block 288 ( 3.1%) 6 48
-GenericBound 352 ( 3.8%) 4 88
-- Trait 352 ( 3.8%) 4
-AssocItem 416 ( 4.5%) 4 104
-- TyAlias 208 ( 2.3%) 2
-- Fn 208 ( 2.3%) 2
-GenericParam 520 ( 5.7%) 5 104
-PathSegment 792 ( 8.6%) 33 24
-Pat 840 ( 9.1%) 7 120
-- Struct 120 ( 1.3%) 1
-- Wild 120 ( 1.3%) 1
-- Ident 600 ( 6.5%) 5
-Expr 936 (10.2%) 9 104
-- Path 104 ( 1.1%) 1
-- Match 104 ( 1.1%) 1
-- Struct 104 ( 1.1%) 1
-- InlineAsm 104 ( 1.1%) 1
-- Lit 208 ( 2.3%) 2
-- Block 312 ( 3.4%) 3
-Ty 1_344 (14.6%) 14 96
-- Rptr 96 ( 1.0%) 1
-- Ptr 96 ( 1.0%) 1
-- ImplicitSelf 192 ( 2.1%) 2
-- Path 960 (10.5%) 10
-Item 2_024 (22.0%) 11 184
-- Trait 184 ( 2.0%) 1
-- Enum 184 ( 2.0%) 1
-- ExternCrate 184 ( 2.0%) 1
-- ForeignMod 184 ( 2.0%) 1
-- Impl 184 ( 2.0%) 1
-- Fn 368 ( 4.0%) 2
-- Use 736 ( 8.0%) 4
-----------------------------------------------------------------
-Total 9_184
-
-
-HIR STATS
-
-Name Accumulated Size Count Item Size
-----------------------------------------------------------------
-Param 64 ( 0.7%) 2 32
-Local 64 ( 0.7%) 1 64
-ForeignItem 72 ( 0.8%) 1 72
-FieldDef 96 ( 1.0%) 2 48
-Arm 96 ( 1.0%) 2 48
-Stmt 96 ( 1.0%) 3 32
-FnDecl 120 ( 1.3%) 3 40
-Attribute 128 ( 1.4%) 4 32
-Lifetime 128 ( 1.4%) 4 32
-Variant 160 ( 1.7%) 2 80
-ImplItem 176 ( 1.9%) 2 88
-GenericBound 192 ( 2.1%) 4 48
-TraitItem 192 ( 2.1%) 2 96
-WherePredicate 216 ( 2.3%) 3 72
-Block 288 ( 3.1%) 6 48
-QPath 408 ( 4.4%) 17 24
-Pat 440 ( 4.8%) 5 88
-Expr 672 ( 7.3%) 12 56
-Item 960 (10.4%) 12 80
-Ty 1_152 (12.4%) 16 72
-Path 1_296 (14.0%) 27 48
-PathSegment 2_240 (24.2%) 40 56
-----------------------------------------------------------------
-Total 9_256
-
+ast-stats-1 PRE EXPANSION AST STATS
+ast-stats-1 Name Accumulated Size Count Item Size
+ast-stats-1 ----------------------------------------------------------------
+ast-stats-1 ExprField 48 ( 0.6%) 1 48
+ast-stats-1 Crate 56 ( 0.7%) 1 56
+ast-stats-1 Attribute 64 ( 0.8%) 2 32
+ast-stats-1 - Normal 32 ( 0.4%) 1
+ast-stats-1 - DocComment 32 ( 0.4%) 1
+ast-stats-1 GenericArgs 64 ( 0.8%) 1 64
+ast-stats-1 - AngleBracketed 64 ( 0.8%) 1
+ast-stats-1 Local 72 ( 0.9%) 1 72
+ast-stats-1 WherePredicate 72 ( 0.9%) 1 72
+ast-stats-1 - BoundPredicate 72 ( 0.9%) 1
+ast-stats-1 Arm 96 ( 1.1%) 2 48
+ast-stats-1 ForeignItem 96 ( 1.1%) 1 96
+ast-stats-1 - Fn 96 ( 1.1%) 1
+ast-stats-1 FieldDef 160 ( 1.9%) 2 80
+ast-stats-1 Stmt 160 ( 1.9%) 5 32
+ast-stats-1 - Local 32 ( 0.4%) 1
+ast-stats-1 - MacCall 32 ( 0.4%) 1
+ast-stats-1 - Expr 96 ( 1.1%) 3
+ast-stats-1 Param 160 ( 1.9%) 4 40
+ast-stats-1 FnDecl 200 ( 2.4%) 5 40
+ast-stats-1 Variant 240 ( 2.8%) 2 120
+ast-stats-1 Block 288 ( 3.4%) 6 48
+ast-stats-1 GenericBound 352 ( 4.2%) 4 88
+ast-stats-1 - Trait 352 ( 4.2%) 4
+ast-stats-1 AssocItem 416 ( 4.9%) 4 104
+ast-stats-1 - TyAlias 208 ( 2.5%) 2
+ast-stats-1 - Fn 208 ( 2.5%) 2
+ast-stats-1 GenericParam 520 ( 6.1%) 5 104
+ast-stats-1 PathSegment 720 ( 8.5%) 30 24
+ast-stats-1 Expr 832 ( 9.8%) 8 104
+ast-stats-1 - Path 104 ( 1.2%) 1
+ast-stats-1 - Match 104 ( 1.2%) 1
+ast-stats-1 - Struct 104 ( 1.2%) 1
+ast-stats-1 - Lit 208 ( 2.5%) 2
+ast-stats-1 - Block 312 ( 3.7%) 3
+ast-stats-1 Pat 840 ( 9.9%) 7 120
+ast-stats-1 - Struct 120 ( 1.4%) 1
+ast-stats-1 - Wild 120 ( 1.4%) 1
+ast-stats-1 - Ident 600 ( 7.1%) 5
+ast-stats-1 Ty 1_344 (15.9%) 14 96
+ast-stats-1 - Rptr 96 ( 1.1%) 1
+ast-stats-1 - Ptr 96 ( 1.1%) 1
+ast-stats-1 - ImplicitSelf 192 ( 2.3%) 2
+ast-stats-1 - Path 960 (11.4%) 10
+ast-stats-1 Item 1_656 (19.6%) 9 184
+ast-stats-1 - Trait 184 ( 2.2%) 1
+ast-stats-1 - Enum 184 ( 2.2%) 1
+ast-stats-1 - ForeignMod 184 ( 2.2%) 1
+ast-stats-1 - Impl 184 ( 2.2%) 1
+ast-stats-1 - Fn 368 ( 4.4%) 2
+ast-stats-1 - Use 552 ( 6.5%) 3
+ast-stats-1 ----------------------------------------------------------------
+ast-stats-1 Total 8_456
+ast-stats-1
+ast-stats-2 POST EXPANSION AST STATS
+ast-stats-2 Name Accumulated Size Count Item Size
+ast-stats-2 ----------------------------------------------------------------
+ast-stats-2 ExprField 48 ( 0.5%) 1 48
+ast-stats-2 Crate 56 ( 0.6%) 1 56
+ast-stats-2 GenericArgs 64 ( 0.7%) 1 64
+ast-stats-2 - AngleBracketed 64 ( 0.7%) 1
+ast-stats-2 Local 72 ( 0.8%) 1 72
+ast-stats-2 WherePredicate 72 ( 0.8%) 1 72
+ast-stats-2 - BoundPredicate 72 ( 0.8%) 1
+ast-stats-2 Arm 96 ( 1.0%) 2 48
+ast-stats-2 ForeignItem 96 ( 1.0%) 1 96
+ast-stats-2 - Fn 96 ( 1.0%) 1
+ast-stats-2 InlineAsm 120 ( 1.3%) 1 120
+ast-stats-2 Attribute 128 ( 1.4%) 4 32
+ast-stats-2 - DocComment 32 ( 0.3%) 1
+ast-stats-2 - Normal 96 ( 1.0%) 3
+ast-stats-2 FieldDef 160 ( 1.7%) 2 80
+ast-stats-2 Stmt 160 ( 1.7%) 5 32
+ast-stats-2 - Local 32 ( 0.3%) 1
+ast-stats-2 - Semi 32 ( 0.3%) 1
+ast-stats-2 - Expr 96 ( 1.0%) 3
+ast-stats-2 Param 160 ( 1.7%) 4 40
+ast-stats-2 FnDecl 200 ( 2.2%) 5 40
+ast-stats-2 Variant 240 ( 2.6%) 2 120
+ast-stats-2 Block 288 ( 3.1%) 6 48
+ast-stats-2 GenericBound 352 ( 3.8%) 4 88
+ast-stats-2 - Trait 352 ( 3.8%) 4
+ast-stats-2 AssocItem 416 ( 4.5%) 4 104
+ast-stats-2 - TyAlias 208 ( 2.3%) 2
+ast-stats-2 - Fn 208 ( 2.3%) 2
+ast-stats-2 GenericParam 520 ( 5.7%) 5 104
+ast-stats-2 PathSegment 792 ( 8.6%) 33 24
+ast-stats-2 Pat 840 ( 9.1%) 7 120
+ast-stats-2 - Struct 120 ( 1.3%) 1
+ast-stats-2 - Wild 120 ( 1.3%) 1
+ast-stats-2 - Ident 600 ( 6.5%) 5
+ast-stats-2 Expr 936 (10.2%) 9 104
+ast-stats-2 - Path 104 ( 1.1%) 1
+ast-stats-2 - Match 104 ( 1.1%) 1
+ast-stats-2 - Struct 104 ( 1.1%) 1
+ast-stats-2 - InlineAsm 104 ( 1.1%) 1
+ast-stats-2 - Lit 208 ( 2.3%) 2
+ast-stats-2 - Block 312 ( 3.4%) 3
+ast-stats-2 Ty 1_344 (14.6%) 14 96
+ast-stats-2 - Rptr 96 ( 1.0%) 1
+ast-stats-2 - Ptr 96 ( 1.0%) 1
+ast-stats-2 - ImplicitSelf 192 ( 2.1%) 2
+ast-stats-2 - Path 960 (10.5%) 10
+ast-stats-2 Item 2_024 (22.0%) 11 184
+ast-stats-2 - Trait 184 ( 2.0%) 1
+ast-stats-2 - Enum 184 ( 2.0%) 1
+ast-stats-2 - ExternCrate 184 ( 2.0%) 1
+ast-stats-2 - ForeignMod 184 ( 2.0%) 1
+ast-stats-2 - Impl 184 ( 2.0%) 1
+ast-stats-2 - Fn 368 ( 4.0%) 2
+ast-stats-2 - Use 736 ( 8.0%) 4
+ast-stats-2 ----------------------------------------------------------------
+ast-stats-2 Total 9_184
+ast-stats-2
+hir-stats HIR STATS
+hir-stats Name Accumulated Size Count Item Size
+hir-stats ----------------------------------------------------------------
+hir-stats ForeignItemRef 24 ( 0.2%) 1 24
+hir-stats Mod 32 ( 0.3%) 1 32
+hir-stats ExprField 40 ( 0.4%) 1 40
+hir-stats TraitItemRef 56 ( 0.5%) 2 28
+hir-stats Param 64 ( 0.6%) 2 32
+hir-stats Local 64 ( 0.6%) 1 64
+hir-stats InlineAsm 72 ( 0.7%) 1 72
+hir-stats ImplItemRef 72 ( 0.7%) 2 36
+hir-stats FieldDef 96 ( 0.9%) 2 48
+hir-stats Arm 96 ( 0.9%) 2 48
+hir-stats Body 96 ( 0.9%) 3 32
+hir-stats Stmt 96 ( 0.9%) 3 32
+hir-stats - Local 32 ( 0.3%) 1
+hir-stats - Semi 32 ( 0.3%) 1
+hir-stats - Expr 32 ( 0.3%) 1
+hir-stats FnDecl 120 ( 1.2%) 3 40
+hir-stats Attribute 128 ( 1.3%) 4 32
+hir-stats GenericArgs 144 ( 1.4%) 3 48
+hir-stats Variant 160 ( 1.6%) 2 80
+hir-stats GenericArg 160 ( 1.6%) 4 40
+hir-stats - Type 40 ( 0.4%) 1
+hir-stats - Lifetime 120 ( 1.2%) 3
+hir-stats GenericBound 192 ( 1.9%) 4 48
+hir-stats - Trait 192 ( 1.9%) 4
+hir-stats WherePredicate 216 ( 2.1%) 3 72
+hir-stats - BoundPredicate 216 ( 2.1%) 3
+hir-stats Block 288 ( 2.8%) 6 48
+hir-stats GenericParam 400 ( 3.9%) 5 80
+hir-stats Pat 440 ( 4.3%) 5 88
+hir-stats - Wild 88 ( 0.9%) 1
+hir-stats - Struct 88 ( 0.9%) 1
+hir-stats - Binding 264 ( 2.6%) 3
+hir-stats Generics 560 ( 5.5%) 10 56
+hir-stats Expr 768 ( 7.5%) 12 64
+hir-stats - Path 64 ( 0.6%) 1
+hir-stats - Struct 64 ( 0.6%) 1
+hir-stats - Match 64 ( 0.6%) 1
+hir-stats - InlineAsm 64 ( 0.6%) 1
+hir-stats - Lit 128 ( 1.3%) 2
+hir-stats - Block 384 ( 3.8%) 6
+hir-stats Item 960 ( 9.4%) 12 80
+hir-stats - Trait 80 ( 0.8%) 1
+hir-stats - Enum 80 ( 0.8%) 1
+hir-stats - ExternCrate 80 ( 0.8%) 1
+hir-stats - ForeignMod 80 ( 0.8%) 1
+hir-stats - Impl 80 ( 0.8%) 1
+hir-stats - Fn 160 ( 1.6%) 2
+hir-stats - Use 400 ( 3.9%) 5
+hir-stats Ty 1_080 (10.6%) 15 72
+hir-stats - Ptr 72 ( 0.7%) 1
+hir-stats - Rptr 72 ( 0.7%) 1
+hir-stats - Path 936 ( 9.2%) 13
+hir-stats Path 1_536 (15.1%) 32 48
+hir-stats PathSegment 2_240 (22.0%) 40 56
+hir-stats ----------------------------------------------------------------
+hir-stats Total 10_200
+hir-stats
help: remove the extra argument
|
LL | let _: Option<(i32, bool)> = Some(/* (i32, bool) */);
- | ~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~
error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/args-instead-of-tuple-errors.rs:8:5
help: remove the extra argument
|
LL | int_bool(/* (i32, bool) */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~
error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied
--> $DIR/args-instead-of-tuple-errors.rs:11:28
help: provide the argument
|
LL | let _: Option<(i8,)> = Some(/* (i8,) */);
- | ~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~
error[E0308]: mismatched types
--> $DIR/args-instead-of-tuple-errors.rs:14:34
help: provide the argument
|
LL | let _: Option<()> = Some(());
- | ~~~~~~~~
+ | ~~~~
error[E0308]: mismatched types
--> $DIR/args-instead-of-tuple.rs:14:34
| |
| required by a bound introduced by this call
|
- = help: the trait `Future` is not implemented for `fn() -> impl Future<Output = ()> {foo}`
+ = help: the trait `Future` is not implemented for fn item `fn() -> impl Future<Output = ()> {foo}`
= note: fn() -> impl Future<Output = ()> {foo} must be a future or must implement `IntoFuture` to be awaited
note: required by a bound in `bar`
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
| |
| required by a bound introduced by this call
|
- = help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]`
+ = help: the trait `Future` is not implemented for closure `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]`
= note: [closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33] must be a future or must implement `IntoFuture` to be awaited
note: required by a bound in `bar`
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
--- /dev/null
+// run-rustfix
+
+fn expect<T>(_: T) {}
+
+fn main() {
+ let x = Some(&());
+ expect::<Option<()>>(x.copied());
+ //~^ ERROR mismatched types
+ //~| HELP use `Option::copied` to copy the value inside the `Option`
+ let x = Ok(&());
+ expect::<Result<(), ()>>(x.copied());
+ //~^ ERROR mismatched types
+ //~| HELP use `Result::copied` to copy the value inside the `Result`
+ let s = String::new();
+ let x = Some(&s);
+ expect::<Option<String>>(x.cloned());
+ //~^ ERROR mismatched types
+ //~| HELP use `Option::cloned` to clone the value inside the `Option`
+ let x = Ok(&s);
+ expect::<Result<String, ()>>(x.cloned());
+ //~^ ERROR mismatched types
+ //~| HELP use `Result::cloned` to clone the value inside the `Result`
+}
--- /dev/null
+// run-rustfix
+
+fn expect<T>(_: T) {}
+
+fn main() {
+ let x = Some(&());
+ expect::<Option<()>>(x);
+ //~^ ERROR mismatched types
+ //~| HELP use `Option::copied` to copy the value inside the `Option`
+ let x = Ok(&());
+ expect::<Result<(), ()>>(x);
+ //~^ ERROR mismatched types
+ //~| HELP use `Result::copied` to copy the value inside the `Result`
+ let s = String::new();
+ let x = Some(&s);
+ expect::<Option<String>>(x);
+ //~^ ERROR mismatched types
+ //~| HELP use `Option::cloned` to clone the value inside the `Option`
+ let x = Ok(&s);
+ expect::<Result<String, ()>>(x);
+ //~^ ERROR mismatched types
+ //~| HELP use `Result::cloned` to clone the value inside the `Result`
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/copied-and-cloned.rs:7:26
+ |
+LL | expect::<Option<()>>(x);
+ | -------------------- ^ expected `()`, found `&()`
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected enum `Option<()>`
+ found enum `Option<&()>`
+note: function defined here
+ --> $DIR/copied-and-cloned.rs:3:4
+ |
+LL | fn expect<T>(_: T) {}
+ | ^^^^^^ ----
+help: use `Option::copied` to copy the value inside the `Option`
+ |
+LL | expect::<Option<()>>(x.copied());
+ | +++++++++
+
+error[E0308]: mismatched types
+ --> $DIR/copied-and-cloned.rs:11:30
+ |
+LL | expect::<Result<(), ()>>(x);
+ | ------------------------ ^ expected `()`, found `&()`
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected enum `Result<(), ()>`
+ found enum `Result<&(), _>`
+note: function defined here
+ --> $DIR/copied-and-cloned.rs:3:4
+ |
+LL | fn expect<T>(_: T) {}
+ | ^^^^^^ ----
+help: use `Result::copied` to copy the value inside the `Result`
+ |
+LL | expect::<Result<(), ()>>(x.copied());
+ | +++++++++
+
+error[E0308]: mismatched types
+ --> $DIR/copied-and-cloned.rs:16:30
+ |
+LL | expect::<Option<String>>(x);
+ | ------------------------ ^ expected struct `String`, found `&String`
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected enum `Option<String>`
+ found enum `Option<&String>`
+note: function defined here
+ --> $DIR/copied-and-cloned.rs:3:4
+ |
+LL | fn expect<T>(_: T) {}
+ | ^^^^^^ ----
+help: use `Option::cloned` to clone the value inside the `Option`
+ |
+LL | expect::<Option<String>>(x.cloned());
+ | +++++++++
+
+error[E0308]: mismatched types
+ --> $DIR/copied-and-cloned.rs:20:34
+ |
+LL | expect::<Result<String, ()>>(x);
+ | ---------------------------- ^ expected struct `String`, found `&String`
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected enum `Result<String, ()>`
+ found enum `Result<&String, _>`
+note: function defined here
+ --> $DIR/copied-and-cloned.rs:3:4
+ |
+LL | fn expect<T>(_: T) {}
+ | ^^^^^^ ----
+help: use `Result::cloned` to clone the value inside the `Result`
+ |
+LL | expect::<Result<String, ()>>(x.cloned());
+ | +++++++++
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+fn main() {
+ let vec = Vec::new();
+ Vec::contains(&vec, &0);
+ //~^ ERROR no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope
+ //~| HELP the function `contains` is implemented on `[_]`
+}
--- /dev/null
+error[E0599]: no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope
+ --> $DIR/deref-path-method.rs:3:10
+ |
+LL | Vec::contains(&vec, &0);
+ | ^^^^^^^^ function or associated item not found in `Vec<_, _>`
+ |
+help: the function `contains` is implemented on `[_]`
+ |
+LL | <[_]>::contains(&vec, &0);
+ | ~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
| --- consider calling this function
...
LL | bar(foo);
- | --- ^^^ the trait `T` is not implemented for `fn() -> impl T<O = ()> {foo}`
+ | --- ^^^ the trait `T` is not implemented for fn item `fn() -> impl T<O = ()> {foo}`
| |
| required by a bound introduced by this call
|
LL | let closure = || S;
| -- consider calling this closure
LL | bar(closure);
- | --- ^^^^^^^ the trait `T` is not implemented for `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]`
+ | --- ^^^^^^^ the trait `T` is not implemented for closure `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]`
| |
| required by a bound introduced by this call
|
//! provided indirectly through an abstraction.
#![crate_type = "lib"]
+#![feature(adt_const_params)]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
Src,
Dst,
Context,
- const ASSUME_ALIGNMENT: bool,
- const ASSUME_LIFETIMES: bool,
- const ASSUME_VALIDITY: bool,
- const ASSUME_VISIBILITY: bool,
+ const ASSUME: std::mem::Assume,
>()
where
Dst: BikeshedIntrinsicFrom<
Src,
Context,
- ASSUME_ALIGNMENT,
- ASSUME_LIFETIMES,
- ASSUME_VALIDITY,
- ASSUME_VISIBILITY,
+ ASSUME,
>,
{}
}
#[repr(C)] struct Src;
#[repr(C)] struct Dst;
- assert::is_transmutable::<Src, Dst, Context, false, false, false, false>();
+ assert::is_transmutable::<Src, Dst, Context, { std::mem::Assume::NOTHING }>();
}
fn via_const() {
const FALSE: bool = false;
- assert::is_transmutable::<Src, Dst, Context, FALSE, FALSE, FALSE, FALSE>();
+ assert::is_transmutable::<Src, Dst, Context, { std::mem::Assume::NOTHING }>();
}
fn via_associated_const() {
Src,
Dst,
Context,
- {Ty::FALSE},
- {Ty::FALSE},
- {Ty::FALSE},
- {Ty::FALSE}
+ {
+ std::mem::Assume {
+ alignment: {Ty::FALSE},
+ lifetimes: {Ty::FALSE},
+ safety: {Ty::FALSE},
+ validity: {Ty::FALSE},
+ }
+ }
>();
}
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn array_like<T, E, const N: usize>()
where
- T: BikeshedIntrinsicFrom<[E; N], Context, false, false, false, true>,
- [E; N]: BikeshedIntrinsicFrom<T, Context, false, false, false, true>
+ T: BikeshedIntrinsicFrom<[E; N], Context, { Assume::SAFETY }>,
+ [E; N]: BikeshedIntrinsicFrom<T, Context, { Assume::SAFETY }>
{}
}
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY.and(Assume::VALIDITY) }>
{}
}
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume::ALIGNMENT
+ .and(Assume::LIFETIMES)
+ .and(Assume::SAFETY)
+ .and(Assume::VALIDITY)
+ }>
{}
}
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume::ALIGNMENT
+ .and(Assume::LIFETIMES)
+ .and(Assume::SAFETY)
+ .and(Assume::VALIDITY)
+ }>
{}
}
error[E0277]: `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:21:52
+ --> $DIR/should_require_well_defined_layout.rs:26:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume::ALIGNMENT
+LL | | .and(Assume::LIFETIMES)
+LL | | .and(Assume::SAFETY)
+LL | | .and(Assume::VALIDITY)
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:22:47
+ --> $DIR/should_require_well_defined_layout.rs:27:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 0]`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `[String; 0]`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume::ALIGNMENT
+LL | | .and(Assume::LIFETIMES)
+LL | | .and(Assume::SAFETY)
+LL | | .and(Assume::VALIDITY)
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:27:52
+ --> $DIR/should_require_well_defined_layout.rs:32:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume::ALIGNMENT
+LL | | .and(Assume::LIFETIMES)
+LL | | .and(Assume::SAFETY)
+LL | | .and(Assume::VALIDITY)
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:28:47
+ --> $DIR/should_require_well_defined_layout.rs:33:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 1]`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `[String; 1]`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume::ALIGNMENT
+LL | | .and(Assume::LIFETIMES)
+LL | | .and(Assume::SAFETY)
+LL | | .and(Assume::VALIDITY)
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:33:52
+ --> $DIR/should_require_well_defined_layout.rs:38:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume::ALIGNMENT
+LL | | .and(Assume::LIFETIMES)
+LL | | .and(Assume::SAFETY)
+LL | | .and(Assume::VALIDITY)
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:34:47
+ --> $DIR/should_require_well_defined_layout.rs:39:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 2]`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `[String; 2]`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume::ALIGNMENT
+LL | | .and(Assume::LIFETIMES)
+LL | | .and(Assume::SAFETY)
+LL | | .and(Assume::VALIDITY)
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error: aborting due to 6 previous errors
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume {
+ alignment: true,
+ lifetimes: true,
+ safety: true,
+ validity: true,
+ }
+ }>
{}
}
error[E0277]: `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:41:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:48:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, true, true, true, true>` is not implemented for `V0i8`
+ = help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `V0i8`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:43:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:50:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<V0i8, n8::Context, true, true, true, true>` is not implemented for `u16`
+ = help: the trait `BikeshedIntrinsicFrom<V0i8, n8::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u16`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:49:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:56:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, true, true, true, true>` is not implemented for `V0u8`
+ = help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `V0u8`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:51:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:58:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<V0u8, n8::Context, true, true, true, true>` is not implemented for `u16`
+ = help: the trait `BikeshedIntrinsicFrom<V0u8, n8::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u16`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:65:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:72:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, true, true, true, true>` is not implemented for `V0i16`
+ = help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `V0i16`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:67:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:74:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<V0i16, n16::Context, true, true, true, true>` is not implemented for `u32`
+ = help: the trait `BikeshedIntrinsicFrom<V0i16, n16::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:73:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:80:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, true, true, true, true>` is not implemented for `V0u16`
+ = help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `V0u16`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:75:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:82:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<V0u16, n16::Context, true, true, true, true>` is not implemented for `u32`
+ = help: the trait `BikeshedIntrinsicFrom<V0u16, n16::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:89:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:96:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, true, true, true, true>` is not implemented for `V0i32`
+ = help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `V0i32`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:91:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:98:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<V0i32, n32::Context, true, true, true, true>` is not implemented for `u64`
+ = help: the trait `BikeshedIntrinsicFrom<V0i32, n32::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:97:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:104:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, true, true, true, true>` is not implemented for `V0u32`
+ = help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `V0u32`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:99:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:106:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<V0u32, n32::Context, true, true, true, true>` is not implemented for `u64`
+ = help: the trait `BikeshedIntrinsicFrom<V0u32, n32::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:113:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:120:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, true, true, true, true>` is not implemented for `V0i64`
+ = help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `V0i64`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:115:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:122:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<V0i64, n64::Context, true, true, true, true>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<V0i64, n64::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:121:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:128:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, true, true, true, true>` is not implemented for `V0u64`
+ = help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `V0u64`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:123:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:130:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<V0u64, n64::Context, true, true, true, true>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<V0u64, n64::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:137:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:144:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, true, true, true, true>` is not implemented for `V0isize`
+ = help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `V0isize`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:139:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:146:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<V0isize, nsize::Context, true, true, true, true>` is not implemented for `[usize; 2]`
+ = help: the trait `BikeshedIntrinsicFrom<V0isize, nsize::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `[usize; 2]`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:145:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:152:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, true, true, true, true>` is not implemented for `V0usize`
+ = help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `V0usize`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
- --> $DIR/primitive_reprs_should_have_correct_length.rs:147:44
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:154:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<V0usize, nsize::Context, true, true, true, true>` is not implemented for `[usize; 2]`
+ = help: the trait `BikeshedIntrinsicFrom<V0usize, nsize::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `[usize; 2]`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error: aborting due to 20 previous errors
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume {
+ alignment: true,
+ lifetimes: true,
+ safety: true,
+ validity: true,
+ }
+ }>
{}
}
error[E0277]: `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:21:52
+ --> $DIR/should_require_well_defined_layout.rs:28:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<void::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<void::repr_rust, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:22:47
+ --> $DIR/should_require_well_defined_layout.rs:29:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `void::repr_rust`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `void::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:27:52
+ --> $DIR/should_require_well_defined_layout.rs:34:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<singleton::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<singleton::repr_rust, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:28:47
+ --> $DIR/should_require_well_defined_layout.rs:35:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `singleton::repr_rust`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `singleton::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:33:52
+ --> $DIR/should_require_well_defined_layout.rs:40:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<duplex::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<duplex::repr_rust, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:34:47
+ --> $DIR/should_require_well_defined_layout.rs:41:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `duplex::repr_rust`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `duplex::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error: aborting due to 6 previous errors
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume::ALIGNMENT
+ .and(Assume::LIFETIMES)
+ .and(Assume::SAFETY)
+ .and(Assume::VALIDITY)
+ }>
{}
}
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume::ALIGNMENT
+ .and(Assume::LIFETIMES)
+ .and(Assume::SAFETY)
+ .and(Assume::VALIDITY)
+ }>
{}
}
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
- --> $DIR/should_pad_variants.rs:39:36
+ --> $DIR/should_pad_variants.rs:44:36
|
LL | assert::is_transmutable::<Src, Dst, Context>();
| ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, true, true, true, true>` is not implemented for `Dst`
+ = help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_pad_variants.rs:13:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume::ALIGNMENT
+LL | | .and(Assume::LIFETIMES)
+LL | | .and(Assume::SAFETY)
+LL | | .and(Assume::VALIDITY)
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error: aborting due to previous error
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume::ALIGNMENT
+ .and(Assume::LIFETIMES)
+ .and(Assume::SAFETY)
+ .and(Assume::VALIDITY)
+ }>
{}
}
error[E0277]: `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
- --> $DIR/should_respect_endianness.rs:32:36
+ --> $DIR/should_respect_endianness.rs:37:36
|
LL | assert::is_transmutable::<Src, Unexpected>();
| ^^^^^^^^^^ `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<Src, assert::Context, true, true, true, true>` is not implemented for `Unexpected`
+ = help: the trait `BikeshedIntrinsicFrom<Src, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `Unexpected`
note: required by a bound in `is_transmutable`
--> $DIR/should_respect_endianness.rs:15:14
|
-LL | pub fn is_transmutable<Src, Dst>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume::ALIGNMENT
+LL | | .and(Assume::LIFETIMES)
+LL | | .and(Assume::SAFETY)
+LL | | .and(Assume::VALIDITY)
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error: aborting due to previous error
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ Dst: BikeshedIntrinsicFrom<Src, Context>
{}
}
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ Dst: BikeshedIntrinsicFrom<Src, Context>
{}
}
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ Dst: BikeshedIntrinsicFrom<Src, Context>
{}
}
//! provided.
#![crate_type = "lib"]
+#![feature(adt_const_params)]
+#![feature(generic_const_exprs)]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub fn is_transmutable<
Src,
Context,
const ASSUME_ALIGNMENT: bool,
const ASSUME_LIFETIMES: bool,
+ const ASSUME_SAFETY: bool,
const ASSUME_VALIDITY: bool,
- const ASSUME_VISIBILITY: bool,
>()
where
Dst: BikeshedIntrinsicFrom<
Src,
Context,
- ASSUME_ALIGNMENT,
- ASSUME_LIFETIMES,
- ASSUME_VALIDITY,
- ASSUME_VISIBILITY,
+ { from_options(ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_SAFETY, ASSUME_VALIDITY) }
+ //~^ ERROR E0080
+ //~| ERROR E0080
+ //~| ERROR E0080
+ //~| ERROR E0080
>,
{}
+
+ const fn from_options(
+ alignment: bool,
+ lifetimes: bool,
+ safety: bool,
+ validity: bool,
+ ) -> Assume {
+ Assume {
+ alignment,
+ lifetimes,
+ safety,
+ validity,
+ }
+ }
}
fn test() {
error[E0308]: mismatched types
- --> $DIR/wrong-type-assume.rs:36:51
+ --> $DIR/wrong-type-assume.rs:53:51
|
LL | assert::is_transmutable::<Src, Dst, Context, {0u8}, false, false, false>();
| ^^^ expected `bool`, found `u8`
+error[E0080]: evaluation of `assert::is_transmutable::<test::Src, test::Dst, test::Context, {0u8}, false, false, false>::{constant#0}` failed
+ --> $DIR/wrong-type-assume.rs:26:15
+ |
+LL | { from_options(ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_SAFETY, ASSUME_VALIDITY) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
error[E0308]: mismatched types
- --> $DIR/wrong-type-assume.rs:37:58
+ --> $DIR/wrong-type-assume.rs:54:58
|
LL | assert::is_transmutable::<Src, Dst, Context, false, {0u8}, false, false>();
| ^^^ expected `bool`, found `u8`
+error[E0080]: evaluation of `assert::is_transmutable::<test::Src, test::Dst, test::Context, false, {0u8}, false, false>::{constant#0}` failed
+ --> $DIR/wrong-type-assume.rs:26:15
+ |
+LL | { from_options(ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_SAFETY, ASSUME_VALIDITY) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
error[E0308]: mismatched types
- --> $DIR/wrong-type-assume.rs:38:65
+ --> $DIR/wrong-type-assume.rs:55:65
|
LL | assert::is_transmutable::<Src, Dst, Context, false, false, {0u8}, false>();
| ^^^ expected `bool`, found `u8`
+error[E0080]: evaluation of `assert::is_transmutable::<test::Src, test::Dst, test::Context, false, false, {0u8}, false>::{constant#0}` failed
+ --> $DIR/wrong-type-assume.rs:26:15
+ |
+LL | { from_options(ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_SAFETY, ASSUME_VALIDITY) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
error[E0308]: mismatched types
- --> $DIR/wrong-type-assume.rs:39:72
+ --> $DIR/wrong-type-assume.rs:56:72
|
LL | assert::is_transmutable::<Src, Dst, Context, false, false, false, {0u8}>();
| ^^^ expected `bool`, found `u8`
-error: aborting due to 4 previous errors
+error[E0080]: evaluation of `assert::is_transmutable::<test::Src, test::Dst, test::Context, false, false, false, {0u8}>::{constant#0}` failed
+ --> $DIR/wrong-type-assume.rs:26:15
+ |
+LL | { from_options(ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_SAFETY, ASSUME_VALIDITY) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
+error: aborting due to 8 previous errors
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0080, E0308.
+For more information about an error, try `rustc --explain E0080`.
#![allow(incomplete_features)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
{}
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY.and(Assume::VALIDITY) }>
{}
}
LL | assert::is_transmutable::<u8, bool>();
| ^^^^ `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, true>` is not implemented for `bool`
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, Assume { alignment: false, lifetimes: false, safety: true, validity: false }>` is not implemented for `bool`
note: required by a bound in `is_transmutable`
--> $DIR/bool.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
pub fn is_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ Dst: BikeshedIntrinsicFrom<Src, Context>
{}
}
LL | assert::is_transmutable::< i8, i16>();
| ^^^ `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i16`
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i16`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:63:40
LL | assert::is_transmutable::< i8, u16>();
| ^^^ `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u16`
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u16`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:64:40
LL | assert::is_transmutable::< i8, i32>();
| ^^^ `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i32`
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:65:40
LL | assert::is_transmutable::< i8, f32>();
| ^^^ `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `f32`
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `f32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:66:40
LL | assert::is_transmutable::< i8, u32>();
| ^^^ `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u32`
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:67:40
LL | assert::is_transmutable::< i8, u64>();
| ^^^ `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u64`
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:68:40
LL | assert::is_transmutable::< i8, i64>();
| ^^^ `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i64`
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:69:40
LL | assert::is_transmutable::< i8, f64>();
| ^^^ `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `f64`
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:70:39
LL | assert::is_transmutable::< i8, u128>();
| ^^^^ `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:71:39
LL | assert::is_transmutable::< i8, i128>();
| ^^^^ `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i128`
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:73:40
LL | assert::is_transmutable::< u8, i16>();
| ^^^ `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i16`
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i16`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:74:40
LL | assert::is_transmutable::< u8, u16>();
| ^^^ `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u16`
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u16`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:75:40
LL | assert::is_transmutable::< u8, i32>();
| ^^^ `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i32`
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:76:40
LL | assert::is_transmutable::< u8, f32>();
| ^^^ `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `f32`
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `f32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:77:40
LL | assert::is_transmutable::< u8, u32>();
| ^^^ `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u32`
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:78:40
LL | assert::is_transmutable::< u8, u64>();
| ^^^ `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u64`
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:79:40
LL | assert::is_transmutable::< u8, i64>();
| ^^^ `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i64`
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:80:40
LL | assert::is_transmutable::< u8, f64>();
| ^^^ `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `f64`
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:81:39
LL | assert::is_transmutable::< u8, u128>();
| ^^^^ `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:82:39
LL | assert::is_transmutable::< u8, i128>();
| ^^^^ `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i128`
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:84:40
LL | assert::is_transmutable::< i16, i32>();
| ^^^ `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i32`
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:85:40
LL | assert::is_transmutable::< i16, f32>();
| ^^^ `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `f32`
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `f32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:86:40
LL | assert::is_transmutable::< i16, u32>();
| ^^^ `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u32`
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:87:40
LL | assert::is_transmutable::< i16, u64>();
| ^^^ `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u64`
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:88:40
LL | assert::is_transmutable::< i16, i64>();
| ^^^ `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i64`
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:89:40
LL | assert::is_transmutable::< i16, f64>();
| ^^^ `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `f64`
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:90:39
LL | assert::is_transmutable::< i16, u128>();
| ^^^^ `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:91:39
LL | assert::is_transmutable::< i16, i128>();
| ^^^^ `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i128`
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:93:40
LL | assert::is_transmutable::< u16, i32>();
| ^^^ `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i32`
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:94:40
LL | assert::is_transmutable::< u16, f32>();
| ^^^ `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `f32`
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `f32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:95:40
LL | assert::is_transmutable::< u16, u32>();
| ^^^ `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u32`
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:96:40
LL | assert::is_transmutable::< u16, u64>();
| ^^^ `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u64`
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:97:40
LL | assert::is_transmutable::< u16, i64>();
| ^^^ `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i64`
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:98:40
LL | assert::is_transmutable::< u16, f64>();
| ^^^ `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `f64`
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:99:39
LL | assert::is_transmutable::< u16, u128>();
| ^^^^ `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:100:39
LL | assert::is_transmutable::< u16, i128>();
| ^^^^ `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i128`
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:102:40
LL | assert::is_transmutable::< i32, u64>();
| ^^^ `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `u64`
+ = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:103:40
LL | assert::is_transmutable::< i32, i64>();
| ^^^ `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `i64`
+ = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:104:40
LL | assert::is_transmutable::< i32, f64>();
| ^^^ `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `f64`
+ = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:105:39
LL | assert::is_transmutable::< i32, u128>();
| ^^^^ `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:106:39
LL | assert::is_transmutable::< i32, i128>();
| ^^^^ `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `i128`
+ = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:108:40
LL | assert::is_transmutable::< f32, u64>();
| ^^^ `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `u64`
+ = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:109:40
LL | assert::is_transmutable::< f32, i64>();
| ^^^ `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `i64`
+ = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:110:40
LL | assert::is_transmutable::< f32, f64>();
| ^^^ `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `f64`
+ = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:111:39
LL | assert::is_transmutable::< f32, u128>();
| ^^^^ `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:112:39
LL | assert::is_transmutable::< f32, i128>();
| ^^^^ `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `i128`
+ = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:114:40
LL | assert::is_transmutable::< u32, u64>();
| ^^^ `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `u64`
+ = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:115:40
LL | assert::is_transmutable::< u32, i64>();
| ^^^ `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `i64`
+ = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:116:40
LL | assert::is_transmutable::< u32, f64>();
| ^^^ `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `f64`
+ = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:117:39
LL | assert::is_transmutable::< u32, u128>();
| ^^^^ `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:118:39
LL | assert::is_transmutable::< u32, i128>();
| ^^^^ `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `i128`
+ = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:120:39
LL | assert::is_transmutable::< u64, u128>();
| ^^^^ `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, false, false, false, false>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:121:39
LL | assert::is_transmutable::< u64, i128>();
| ^^^^ `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, false, false, false, false>` is not implemented for `i128`
+ = help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:123:39
LL | assert::is_transmutable::< i64, u128>();
| ^^^^ `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, false, false, false, false>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:124:39
LL | assert::is_transmutable::< i64, i128>();
| ^^^^ `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, false, false, false, false>` is not implemented for `i128`
+ = help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:126:39
LL | assert::is_transmutable::< f64, u128>();
| ^^^^ `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, false, false, false, false>` is not implemented for `u128`
+ = help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:127:39
LL | assert::is_transmutable::< f64, i128>();
| ^^^^ `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, false, false, false, false>` is not implemented for `i128`
+ = help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to 57 previous errors
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume::ALIGNMENT
+ .and(Assume::LIFETIMES)
+ .and(Assume::SAFETY)
+ .and(Assume::VALIDITY)
+ }>
{}
}
error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`.
- --> $DIR/unit.rs:23:35
+ --> $DIR/unit.rs:28:35
|
LL | assert::is_transmutable::<(), u8, Context>();
| ^^ `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not implemented for `u8`
+ = help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u8`
note: required by a bound in `is_transmutable`
--> $DIR/unit.rs:12:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume::ALIGNMENT
+LL | | .and(Assume::LIFETIMES)
+LL | | .and(Assume::SAFETY)
+LL | | .and(Assume::VALIDITY)
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error: aborting due to previous error
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume {
+ alignment: true,
+ lifetimes: true,
+ safety: true,
+ validity: true,
+ }
+ }>
{}
}
error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`.
- --> $DIR/references.rs:19:52
+ --> $DIR/references.rs:26:52
|
LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
| ^^^^^^^^^^^^^ `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not implemented for `&'static Unit`
+ = help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `&'static Unit`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/references.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error: aborting due to previous error
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume {
+ alignment: true,
+ lifetimes: true,
+ safety: true,
+ validity: true,
+ }
+ }>
{}
}
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume {
+ alignment: true,
+ lifetimes: true,
+ safety: true,
+ validity: true,
+ }
+ }>
{}
}
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume {
+ alignment: true,
+ lifetimes: true,
+ safety: true,
+ validity: true,
+ }
+ }>
{}
}
error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:21:52
+ --> $DIR/should_require_well_defined_layout.rs:28:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::unit::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::unit::repr_rust, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:22:47
+ --> $DIR/should_require_well_defined_layout.rs:29:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::unit::repr_rust`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `should_reject_repr_rust::unit::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:27:52
+ --> $DIR/should_require_well_defined_layout.rs:34:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::tuple::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::tuple::repr_rust, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:28:47
+ --> $DIR/should_require_well_defined_layout.rs:35:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::tuple::repr_rust`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `should_reject_repr_rust::tuple::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:33:52
+ --> $DIR/should_require_well_defined_layout.rs:40:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::braces::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::braces::repr_rust, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:34:47
+ --> $DIR/should_require_well_defined_layout.rs:41:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::braces::repr_rust`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `should_reject_repr_rust::braces::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:39:52
+ --> $DIR/should_require_well_defined_layout.rs:46:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<aligned::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<aligned::repr_rust, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:40:47
+ --> $DIR/should_require_well_defined_layout.rs:47:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `aligned::repr_rust`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `aligned::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:45:52
+ --> $DIR/should_require_well_defined_layout.rs:52:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<packed::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<packed::repr_rust, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:46:47
+ --> $DIR/should_require_well_defined_layout.rs:53:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `packed::repr_rust`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `packed::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:52:49
+ --> $DIR/should_require_well_defined_layout.rs:59:49
|
LL | assert::is_maybe_transmutable::<repr_c, ()>();
| ^^ `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<nested::repr_c, assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<nested::repr_c, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:53:47
+ --> $DIR/should_require_well_defined_layout.rs:60:47
|
LL | assert::is_maybe_transmutable::<u128, repr_c>();
| ^^^^^^ `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `nested::repr_c`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `nested::repr_c`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error: aborting due to 12 previous errors
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume::ALIGNMENT
+ .and(Assume::LIFETIMES)
+ .and(Assume::SAFETY)
+ .and(Assume::VALIDITY)
+ }>
{}
}
#![allow(incomplete_features)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
{}
}
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume {
+ alignment: true,
+ lifetimes: true,
+ safety: true,
+ validity: true,
+ }
+ }>
{}
}
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume {
+ alignment: true,
+ lifetimes: true,
+ safety: true,
+ validity: true,
+ }
+ }>
{}
}
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume {
+ alignment: true,
+ lifetimes: true,
+ safety: true,
+ validity: true,
+ }
+ }>
{}
}
error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:23:48
+ --> $DIR/should_require_well_defined_layout.rs:30:48
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+ = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::repr_rust, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`.
- --> $DIR/should_require_well_defined_layout.rs:24:43
+ --> $DIR/should_require_well_defined_layout.rs:31:43
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::repr_rust`
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `should_reject_repr_rust::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
-LL | pub fn is_maybe_transmutable<Src, Dst>()
- | --------------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume {
+LL | | alignment: true,
+LL | | lifetimes: true,
+... |
+LL | | }
+LL | | }>
+ | |__________^ required by this bound in `is_maybe_transmutable`
error: aborting due to 2 previous errors
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, {
+ Assume::ALIGNMENT
+ .and(Assume::LIFETIMES)
+ .and(Assume::SAFETY)
+ .and(Assume::VALIDITY)
+ }>
{}
}
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
- --> $DIR/should_pad_variants.rs:39:36
+ --> $DIR/should_pad_variants.rs:44:36
|
LL | assert::is_transmutable::<Src, Dst, Context>();
| ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, true, true, true, true>` is not implemented for `Dst`
+ = help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_pad_variants.rs:13:14
|
-LL | pub fn is_transmutable<Src, Dst, Context>()
- | --------------- required by a bound in this
-LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
+ | ______________^
+LL | | Assume::ALIGNMENT
+LL | | .and(Assume::LIFETIMES)
+LL | | .and(Assume::SAFETY)
+LL | | .and(Assume::VALIDITY)
+LL | | }>
+ | |__________^ required by this bound in `is_transmutable`
error: aborting due to previous error
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
- // validity IS assumed --------------------------------^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY.and(Assume::VALIDITY) }>
{}
}
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
{}
}
LL | assert::is_transmutable::<Superset, Subset>();
| ^^^^^^ `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<Superset, assert::Context, false, false, false, true>` is not implemented for `Subset`
+ = help: the trait `BikeshedIntrinsicFrom<Superset, assert::Context, Assume { alignment: false, lifetimes: false, safety: true, validity: false }>` is not implemented for `Subset`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_contraction.rs:13:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
- // validity IS assumed --------------------------------^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY.and(Assume::VALIDITY) }>
{}
}
error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
- --> $DIR/should_reject_disjoint.rs:34:40
+ --> $DIR/should_reject_disjoint.rs:33:40
|
LL | assert::is_maybe_transmutable::<A, B>();
| ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<A, assert::Context, false, false, true, true>` is not implemented for `B`
+ = help: the trait `BikeshedIntrinsicFrom<A, assert::Context, Assume { alignment: false, lifetimes: false, safety: true, validity: true }>` is not implemented for `B`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_reject_disjoint.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY.and(Assume::VALIDITY) }>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
- --> $DIR/should_reject_disjoint.rs:35:40
+ --> $DIR/should_reject_disjoint.rs:34:40
|
LL | assert::is_maybe_transmutable::<B, A>();
| ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<B, assert::Context, false, false, true, true>` is not implemented for `A`
+ = help: the trait `BikeshedIntrinsicFrom<B, assert::Context, Assume { alignment: false, lifetimes: false, safety: true, validity: true }>` is not implemented for `A`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_reject_disjoint.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY.and(Assume::VALIDITY) }>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error: aborting due to 2 previous errors
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
- // validity is NOT assumed ----------------------------^^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
+ // validity is NOT assumed --------------^^^^^^^^^^^^^^^^^^
{}
}
LL | assert::is_transmutable::<A, B>();
| ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<A, assert::Context, false, false, false, true>` is not implemented for `B`
+ = help: the trait `BikeshedIntrinsicFrom<A, assert::Context, Assume { alignment: false, lifetimes: false, safety: true, validity: false }>` is not implemented for `B`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_intersecting.rs:14:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
--> $DIR/should_reject_intersecting.rs:37:34
LL | assert::is_transmutable::<B, A>();
| ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<B, assert::Context, false, false, false, true>` is not implemented for `A`
+ = help: the trait `BikeshedIntrinsicFrom<B, assert::Context, Assume { alignment: false, lifetimes: false, safety: true, validity: false }>` is not implemented for `A`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_intersecting.rs:14:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to 2 previous errors
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
- // visibility IS assumed -------------------------------------^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
+ // safety IS assumed --------------------^^^^^^^^^^^^^^^^^^
{}
}
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
- // visibility IS assumed -------------------------------------^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
+ // safety IS assumed --------------------^^^^^^^^^^^^^^^^^^
{}
}
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
- // visibility IS assumed -------------------------------------^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
+ // safety IS assumed --------------------^^^^^^^^^^^^^^^^^^
{}
}
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
- // visibility IS assumed -------------------------------------^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
+ // safety IS assumed --------------------^^^^^^^^^^^^^^^^^^
{}
}
#![allow(dead_code)]
mod assert {
- use std::mem::BikeshedIntrinsicFrom;
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
- // visibility IS assumed -------------------------------------^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context, { Assume::SAFETY }>
+ // safety IS assumed --------------------^^^^^^^^^^^^^^^^^^
{}
}
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- // visibility is NOT assumed ---------------------------------^^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
{}
}
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- // visibility is NOT assumed ---------------------------------^^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
{}
}
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- // visibility is NOT assumed ---------------------------------^^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
{}
}
error[E0446]: private type `src::Zst` in public interface
- --> $DIR/should_accept_if_src_has_unreachable_field.rs:23:9
+ --> $DIR/should_accept_if_src_has_unreachable_field.rs:22:9
|
LL | #[repr(C)] pub(self) struct Zst; // <- unreachable type
| -------------------- `src::Zst` declared as private
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- // visibility is NOT assumed ---------------------------------^^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
{}
}
error[E0603]: struct `Src` is private
- --> $DIR/should_accept_if_src_has_unreachable_ty.rs:38:36
+ --> $DIR/should_accept_if_src_has_unreachable_ty.rs:37:36
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^ private struct
|
note: the struct `Src` is defined here
- --> $DIR/should_accept_if_src_has_unreachable_ty.rs:23:16
+ --> $DIR/should_accept_if_src_has_unreachable_ty.rs:22:16
|
LL | #[repr(C)] pub(self) struct Src {
| ^^^^^^^^^^^^^^^^^^^^
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- // visibility is NOT assumed ---------------------------------^^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
{}
}
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
- --> $DIR/should_reject_if_dst_has_private_field.rs:36:41
+ --> $DIR/should_reject_if_dst_has_private_field.rs:35:41
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+ = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_if_dst_has_private_field.rs:13:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- // visibility is NOT assumed ---------------------------------^^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
{}
}
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
- --> $DIR/should_reject_if_dst_has_private_variant.rs:37:41
+ --> $DIR/should_reject_if_dst_has_private_variant.rs:36:41
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+ = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_if_dst_has_private_variant.rs:13:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- // visibility is NOT assumed ---------------------------------^^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
{}
}
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- // visibility is NOT assumed ---------------------------------^^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
{}
}
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
- --> $DIR/should_reject_if_dst_has_unreachable_field.rs:38:41
+ --> $DIR/should_reject_if_dst_has_unreachable_field.rs:37:41
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+ = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_if_dst_has_unreachable_field.rs:15:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
pub fn is_transmutable<Src, Dst, Context>()
where
- Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- // visibility is NOT assumed ---------------------------------^^^^^
+ Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
{}
}
error[E0603]: struct `Dst` is private
- --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:46
+ --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:38:46
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^ private struct
|
note: the struct `Dst` is defined here
- --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:32:16
+ --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:31:16
|
LL | #[repr(C)] pub(self) struct Dst {
| ^^^^^^^^^^^^^^^^^^^^
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
- --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:41
+ --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:38:41
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
|
- = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+ = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_if_dst_has_unreachable_ty.rs:15:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
-LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+LL | Dst: BikeshedIntrinsicFrom<Src, Context> // safety is NOT assumed
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to 2 previous errors
error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
--> $DIR/bad-interconversion.rs:11:12
|
-LL | / fn option_to_result() -> Result<u64, String> {
-LL | | Some(3)?;
- | | ^ use `.ok_or(...)?` to provide an error compatible with `Result<u64, String>`
-LL | |
-LL | | Ok(10)
-LL | | }
- | |_- this function returns a `Result`
+LL | fn option_to_result() -> Result<u64, String> {
+ | -------------------------------------------- this function returns a `Result`
+LL | Some(3)?;
+ | ^ use `.ok_or(...)?` to provide an error compatible with `Result<u64, String>`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>`
= help: the following other types implement trait `FromResidual<R>`:
error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result`
--> $DIR/bad-interconversion.rs:17:31
|
-LL | / fn control_flow_to_result() -> Result<u64, String> {
-LL | | Ok(ControlFlow::Break(123)?)
- | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result<u64, String>`
-LL | |
-LL | | }
- | |_- this function returns a `Result`
+LL | fn control_flow_to_result() -> Result<u64, String> {
+ | -------------------------------------------------- this function returns a `Result`
+LL | Ok(ControlFlow::Break(123)?)
+ | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result<u64, String>`
|
= help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>`
= help: the following other types implement trait `FromResidual<R>`:
error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
--> $DIR/bad-interconversion.rs:22:22
|
-LL | / fn result_to_option() -> Option<u16> {
-LL | | Some(Err("hello")?)
- | | ^ use `.ok()?` if you want to discard the `Result<Infallible, &str>` error information
-LL | |
-LL | | }
- | |_- this function returns an `Option`
+LL | fn result_to_option() -> Option<u16> {
+ | ------------------------------------ this function returns an `Option`
+LL | Some(Err("hello")?)
+ | ^ use `.ok()?` if you want to discard the `Result<Infallible, &str>` error information
|
= help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>`
= help: the following other types implement trait `FromResidual<R>`:
error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
--> $DIR/bad-interconversion.rs:27:33
|
-LL | / fn control_flow_to_option() -> Option<u64> {
-LL | | Some(ControlFlow::Break(123)?)
- | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option<u64>`
-LL | |
-LL | | }
- | |_- this function returns an `Option`
+LL | fn control_flow_to_option() -> Option<u64> {
+ | ------------------------------------------ this function returns an `Option`
+LL | Some(ControlFlow::Break(123)?)
+ | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option<u64>`
|
= help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
= help: the following other types implement trait `FromResidual<R>`:
error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
--> $DIR/bad-interconversion.rs:32:39
|
-LL | / fn result_to_control_flow() -> ControlFlow<String> {
-LL | | ControlFlow::Continue(Err("hello")?)
- | | ^ this `?` produces `Result<Infallible, &str>`, which is incompatible with `ControlFlow<String>`
-LL | |
-LL | | }
- | |_- this function returns a `ControlFlow`
+LL | fn result_to_control_flow() -> ControlFlow<String> {
+ | -------------------------------------------------- this function returns a `ControlFlow`
+LL | ControlFlow::Continue(Err("hello")?)
+ | ^ this `?` produces `Result<Infallible, &str>`, which is incompatible with `ControlFlow<String>`
|
= help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `ControlFlow<String>`
= help: the trait `FromResidual` is implemented for `ControlFlow<B, C>`
error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
--> $DIR/bad-interconversion.rs:37:12
|
-LL | / fn option_to_control_flow() -> ControlFlow<u64> {
-LL | | Some(3)?;
- | | ^ this `?` produces `Option<Infallible>`, which is incompatible with `ControlFlow<u64>`
-LL | |
-LL | | ControlFlow::Break(10)
-LL | | }
- | |_- this function returns a `ControlFlow`
+LL | fn option_to_control_flow() -> ControlFlow<u64> {
+ | ----------------------------------------------- this function returns a `ControlFlow`
+LL | Some(3)?;
+ | ^ this `?` produces `Option<Infallible>`, which is incompatible with `ControlFlow<u64>`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `ControlFlow<u64>`
= help: the trait `FromResidual` is implemented for `ControlFlow<B, C>`
error[E0277]: the `?` operator in a function that returns `ControlFlow<B, _>` can only be used on other `ControlFlow<B, _>`s (with the same Break type)
--> $DIR/bad-interconversion.rs:43:29
|
-LL | / fn control_flow_to_control_flow() -> ControlFlow<i64> {
-LL | | ControlFlow::Break(4_u8)?;
- | | ^ this `?` produces `ControlFlow<u8, Infallible>`, which is incompatible with `ControlFlow<i64>`
-LL | |
-LL | | ControlFlow::Continue(())
-LL | | }
- | |_- this function returns a `ControlFlow`
+LL | fn control_flow_to_control_flow() -> ControlFlow<i64> {
+ | ----------------------------------------------------- this function returns a `ControlFlow`
+LL | ControlFlow::Break(4_u8)?;
+ | ^ this `?` produces `ControlFlow<u8, Infallible>`, which is incompatible with `ControlFlow<i64>`
|
= help: the trait `FromResidual<ControlFlow<u8, Infallible>>` is not implemented for `ControlFlow<i64>`
= note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow`
error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
--> $DIR/option-to-result.rs:5:6
|
-LL | / fn test_result() -> Result<(),()> {
-LL | | let a:Option<()> = Some(());
-LL | | a?;
- | | ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>`
-LL | | Ok(())
-LL | | }
- | |_- this function returns a `Result`
+LL | fn test_result() -> Result<(),()> {
+ | --------------------------------- this function returns a `Result`
+LL | let a:Option<()> = Some(());
+LL | a?;
+ | ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>`
= help: the following other types implement trait `FromResidual<R>`:
error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
--> $DIR/option-to-result.rs:11:6
|
-LL | / fn test_option() -> Option<i32>{
-LL | | let a:Result<i32, i32> = Ok(5);
-LL | | a?;
- | | ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information
-LL | | Some(5)
-LL | | }
- | |_- this function returns an `Option`
+LL | fn test_option() -> Option<i32>{
+ | ------------------------------- this function returns an `Option`
+LL | let a:Result<i32, i32> = Ok(5);
+LL | a?;
+ | ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information
|
= help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>`
= help: the following other types implement trait `FromResidual<R>`:
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-diagnostics.rs:7:6
|
-LL | / fn a_function() -> u32 {
-LL | | let x: Option<u32> = None;
-LL | | x?;
- | | ^ cannot use the `?` operator in a function that returns `u32`
-LL | | 22
-LL | | }
- | |_- this function should return `Result` or `Option` to accept `?`
+LL | fn a_function() -> u32 {
+ | ---------------------- this function should return `Result` or `Option` to accept `?`
+LL | let x: Option<u32> = None;
+LL | x?;
+ | ^ cannot use the `?` operator in a function that returns `u32`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-diagnostics.rs:14:10
|
-LL | let a_closure = || {
- | _____________________-
-LL | | let x: Option<u32> = None;
-LL | | x?;
- | | ^ cannot use the `?` operator in a closure that returns `{integer}`
-LL | | 22
-LL | | };
- | |_____- this function should return `Result` or `Option` to accept `?`
+LL | let a_closure = || {
+ | -- this function should return `Result` or `Option` to accept `?`
+LL | let x: Option<u32> = None;
+LL | x?;
+ | ^ cannot use the `?` operator in a closure that returns `{integer}`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-diagnostics.rs:26:14
|
-LL | / fn a_method() {
-LL | | let x: Option<u32> = None;
-LL | | x?;
- | | ^ cannot use the `?` operator in a method that returns `()`
-LL | | }
- | |_________- this function should return `Result` or `Option` to accept `?`
+LL | fn a_method() {
+ | ------------- this function should return `Result` or `Option` to accept `?`
+LL | let x: Option<u32> = None;
+LL | x?;
+ | ^ cannot use the `?` operator in a method that returns `()`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-diagnostics.rs:39:14
|
-LL | / fn a_trait_method() {
-LL | | let x: Option<u32> = None;
-LL | | x?;
- | | ^ cannot use the `?` operator in a trait method that returns `()`
-LL | | }
- | |_________- this function should return `Result` or `Option` to accept `?`
+LL | fn a_trait_method() {
+ | ------------------- this function should return `Result` or `Option` to accept `?`
+LL | let x: Option<u32> = None;
+LL | x?;
+ | ^ cannot use the `?` operator in a trait method that returns `()`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
--> $DIR/try-on-option.rs:5:6
|
-LL | / fn foo() -> Result<u32, ()> {
-LL | | let x: Option<u32> = None;
-LL | | x?;
- | | ^ use `.ok_or(...)?` to provide an error compatible with `Result<u32, ()>`
-LL | | Ok(22)
-LL | | }
- | |_- this function returns a `Result`
+LL | fn foo() -> Result<u32, ()> {
+ | --------------------------- this function returns a `Result`
+LL | let x: Option<u32> = None;
+LL | x?;
+ | ^ use `.ok_or(...)?` to provide an error compatible with `Result<u32, ()>`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>`
= help: the following other types implement trait `FromResidual<R>`:
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option.rs:11:6
|
-LL | / fn bar() -> u32 {
-LL | | let x: Option<u32> = None;
-LL | | x?;
- | | ^ cannot use the `?` operator in a function that returns `u32`
-LL | | 22
-LL | | }
- | |_- this function should return `Result` or `Option` to accept `?`
+LL | fn bar() -> u32 {
+ | --------------- this function should return `Result` or `Option` to accept `?`
+LL | let x: Option<u32> = None;
+LL | x?;
+ | ^ cannot use the `?` operator in a function that returns `u32`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-operator-on-main.rs:7:31
|
-LL | / fn main() {
-LL | | // error for a `Try` type on a non-`Try` fn
-LL | | std::fs::File::open("foo")?;
- | | ^ cannot use the `?` operator in a function that returns `()`
-LL | |
-... |
-LL | | try_trait_generic::<()>();
-LL | | }
- | |_- this function should return `Result` or `Option` to accept `?`
+LL | fn main() {
+ | --------- this function should return `Result` or `Option` to accept `?`
+LL | // error for a `Try` type on a non-`Try` fn
+LL | std::fs::File::open("foo")?;
+ | ^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-operator-on-main.rs:10:7
|
-LL | / fn main() {
-LL | | // error for a `Try` type on a non-`Try` fn
-LL | | std::fs::File::open("foo")?;
-LL | |
-LL | | // a non-`Try` type on a non-`Try` fn
-LL | | ()?;
- | | ^ cannot use the `?` operator in a function that returns `()`
-... |
-LL | | try_trait_generic::<()>();
-LL | | }
- | |_- this function should return `Result` or `Option` to accept `?`
+LL | fn main() {
+ | --------- this function should return `Result` or `Option` to accept `?`
+...
+LL | ()?;
+ | ^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `FromResidual<_>` is not implemented for `()`
help: remove the extra argument
|
LL | groups.push(/* (Vec<String>, Vec<Process>) */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
help: remove the extra argument
|
LL | (|| {})();
- | ~~~~~~~~~
+ | ~~
error: aborting due to previous error
help: provide the argument
|
LL | <E>::V(/* u8 */);
- | ~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~
error[E0308]: mismatched types
--> $DIR/enum-variant-priority-higher-than-other-inherent.rs:22:17
help: remove the extra argument
|
LL | let x: Vec::with_capacity(10);
- | ~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~
error: aborting due to 2 previous errors
--- /dev/null
+// issue #101376
+
+use std::ops::AddAssign;
+struct Foo;
+
+impl AddAssign<()> for Foo {
+ fn add_assign(&mut self, _: ()) {}
+}
+
+impl AddAssign<()> for &mut Foo {
+ fn add_assign(&mut self, _: ()) {}
+}
+
+fn main() {
+ (&mut Foo) += ();
+ //~^ ERROR invalid left-hand side of assignment
+ //~| NOTE cannot assign to this expression
+ //~| HELP consider dereferencing the left-hand side of this operation
+}
--- /dev/null
+error[E0067]: invalid left-hand side of assignment
+ --> $DIR/assign-non-lval-needs-deref.rs:15:16
+ |
+LL | (&mut Foo) += ();
+ | ---------- ^^
+ | |
+ | cannot assign to this expression
+ |
+help: consider dereferencing the left-hand side of this operation
+ |
+LL | *(&mut Foo) += ();
+ | +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0067`.
--- /dev/null
+fn foo<T: std::fmt::Display>() {}
+
+fn main() {
+ let x = foo::<()>;
+ //~^ ERROR `()` doesn't implement `std::fmt::Display`
+}
--- /dev/null
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+ --> $DIR/point-at-type-param-in-path-expr.rs:4:19
+ |
+LL | let x = foo::<()>;
+ | ^^ `()` cannot be formatted with the default formatter
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `()`
+ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `foo`
+ --> $DIR/point-at-type-param-in-path-expr.rs:1:11
+ |
+LL | fn foo<T: std::fmt::Display>() {}
+ | ^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
help: remove the extra argument
|
LL | l(vec![])
- |
+ | ~~~~~~~~
error: aborting due to previous error
help: remove the extra argument
|
LL | let _ = Some(3);
- | ~~~~~~~
+ | ~~~
error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied
--> $DIR/struct-enum-wrong-args.rs:7:13
help: remove the extra arguments
|
LL | let _ = Ok(3);
- | ~~~~~
+ | ~~~
error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied
--> $DIR/struct-enum-wrong-args.rs:8:13
help: provide the argument
|
LL | let _ = Ok(/* value */);
- | ~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~
error[E0061]: this struct takes 1 argument but 0 arguments were supplied
--> $DIR/struct-enum-wrong-args.rs:9:13
help: provide the argument
|
LL | let _ = Wrapper(/* i32 */);
- | ~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~
error[E0061]: this struct takes 1 argument but 2 arguments were supplied
--> $DIR/struct-enum-wrong-args.rs:10:13
help: remove the extra argument
|
LL | let _ = Wrapper(5);
- | ~~~~~~~~~~
+ | ~~~
error[E0061]: this struct takes 2 arguments but 0 arguments were supplied
--> $DIR/struct-enum-wrong-args.rs:11:13
help: provide the arguments
|
LL | let _ = DoubleWrapper(/* i32 */, /* i32 */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~~~~~~~~~
error[E0061]: this struct takes 2 arguments but 1 argument was supplied
--> $DIR/struct-enum-wrong-args.rs:12:13
help: provide the argument
|
LL | let _ = DoubleWrapper(5, /* i32 */);
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~~~~~~~~~
error[E0061]: this struct takes 2 arguments but 3 arguments were supplied
--> $DIR/struct-enum-wrong-args.rs:13:13
help: remove the extra argument
|
LL | let _ = DoubleWrapper(5, 2);
- | ~~~~~~~~~~~~~~~~~~~
+ | ~~~~~~
error: aborting due to 8 previous errors
fn main() {
<i32 as Add<u32>>::add(1, 2);
//~^ ERROR cannot add `u32` to `i32`
+ //~| ERROR cannot add `u32` to `i32`
<i32 as Add<i32>>::add(1u32, 2);
//~^ ERROR mismatched types
<i32 as Add<i32>>::add(1, 2u32);
and 48 others
error[E0308]: mismatched types
- --> $DIR/ufcs-qpath-self-mismatch.rs:6:28
+ --> $DIR/ufcs-qpath-self-mismatch.rs:7:28
|
LL | <i32 as Add<i32>>::add(1u32, 2);
| ---------------------- ^^^^ expected `i32`, found `u32`
| ~~~
error[E0308]: mismatched types
- --> $DIR/ufcs-qpath-self-mismatch.rs:8:31
+ --> $DIR/ufcs-qpath-self-mismatch.rs:9:31
|
LL | <i32 as Add<i32>>::add(1, 2u32);
| ---------------------- ^^^^ expected `i32`, found `u32`
LL | <i32 as Add<i32>>::add(1, 2i32);
| ~~~
-error: aborting due to 3 previous errors
+error[E0277]: cannot add `u32` to `i32`
+ --> $DIR/ufcs-qpath-self-mismatch.rs:4:5
+ |
+LL | <i32 as Add<u32>>::add(1, 2);
+ | ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32`
+ |
+ = help: the trait `Add<u32>` is not implemented for `i32`
+ = help: the following other types implement trait `Add<Rhs>`:
+ <&'a f32 as Add<f32>>
+ <&'a f64 as Add<f64>>
+ <&'a i128 as Add<i128>>
+ <&'a i16 as Add<i16>>
+ <&'a i32 as Add<i32>>
+ <&'a i64 as Add<i64>>
+ <&'a i8 as Add<i8>>
+ <&'a isize as Add<isize>>
+ and 48 others
+
+error: aborting due to 4 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
| |
| required by a bound introduced by this call
|
- = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
+ = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for fn item `for<'r> unsafe fn(&'r isize) -> isize {square}`
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `call_it`
--> $DIR/unboxed-closures-unsafe-extern-fn.rs:9:15
| |
| required by a bound introduced by this call
|
- = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
+ = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for fn item `for<'r> unsafe fn(&'r isize) -> isize {square}`
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `call_it_mut`
--> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:19
| |
| required by a bound introduced by this call
|
- = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
+ = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for fn item `for<'r> unsafe fn(&'r isize) -> isize {square}`
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `call_it_once`
--> $DIR/unboxed-closures-unsafe-extern-fn.rs:15:20
| |
| required by a bound introduced by this call
|
- = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+ = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for fn item `for<'r> extern "C" fn(&'r isize) -> isize {square}`
note: required by a bound in `call_it`
--> $DIR/unboxed-closures-wrong-abi.rs:9:15
|
| |
| required by a bound introduced by this call
|
- = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+ = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for fn item `for<'r> extern "C" fn(&'r isize) -> isize {square}`
note: required by a bound in `call_it_mut`
--> $DIR/unboxed-closures-wrong-abi.rs:12:19
|
| |
| required by a bound introduced by this call
|
- = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+ = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for fn item `for<'r> extern "C" fn(&'r isize) -> isize {square}`
note: required by a bound in `call_it_once`
--> $DIR/unboxed-closures-wrong-abi.rs:15:20
|
| |
| required by a bound introduced by this call
|
- = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
+ = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}`
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `call_it`
--> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:10:15
| |
| required by a bound introduced by this call
|
- = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
+ = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}`
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `call_it_mut`
--> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:19
| |
| required by a bound introduced by this call
|
- = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
+ = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}`
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `call_it_once`
--> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:16:20
| ^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[u8]`
+ = note: all function arguments must have a statically known size
= help: unsized fn params are gated as an unstable feature
-help: function arguments must have a statically known size, borrowed types always have a known size
- |
-LL | &X(&*Y)
- | +
error: aborting due to previous error
-Subproject commit 4ed54cecce3ce9ab6ff058781f4c8a500ee6b8b5
+Subproject commit 646e9a0b9ea8354cc409d05f10e8dc752c5de78e
impl<'tcx> LateLintPass<'tcx> for MyStructLint {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
// Check our expr is calling a method
- if let hir::ExprKind::MethodCall(path, _, [_self_arg, ..]) = &expr.kind
+ if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind
// Check the name of this method is `some_method`
&& path.ident.name == sym!(some_method)
// Optionally, check the type of the self argument.
&& matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro))
&& let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn)
&& matches!(panic_expn, PanicExpn::Empty)
- && let ExprKind::MethodCall(method_segment, [recv], _) = condition.kind
+ && let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind
&& let result_type_with_refs = cx.typeck_results().expr_ty(recv)
&& let result_type = result_type_with_refs.peel_refs()
&& is_type_diagnostic_item(cx, result_type, sym::Result)
// do not lint if the closure is called using an iterator (see #1141)
if_chain! {
if let Some(parent) = get_parent_expr(self.cx, expr);
- if let ExprKind::MethodCall(_, [self_arg, ..], _) = &parent.kind;
+ if let ExprKind::MethodCall(_, self_arg, ..) = &parent.kind;
let caller = self.cx.typeck_results().expr_ty(self_arg);
if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator);
if implements_trait(self.cx, caller, iter_id, &[]);
);
}
} else {
- let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
+ let span =
+ block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
if span.from_expansion() || expr.span.from_expansion() {
return;
}
))
})
},
- ExprKind::MethodCall(path, args, _) if args.len() == 1 => {
- let type_of_receiver = cx.typeck_results().expr_ty(&args[0]);
+ ExprKind::MethodCall(path, receiver, [], _) => {
+ let type_of_receiver = cx.typeck_results().expr_ty(receiver);
if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
&& !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
{
let path: &str = path.ident.name.as_str();
a == path
})
- .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, args[0].span)?, neg_method)))
+ .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, receiver.span)?, neg_method)))
},
_ => None,
}
if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
&& let ty::Int(from) = cast_from.kind()
&& let ty::Uint(to) = cast_to.kind()
- && let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind
+ && let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind
&& method_path.ident.name.as_str() == "abs"
{
let span = if from.bit_width() == to.bit_width() {
span,
&format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
"replace with",
- format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()),
+ format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()),
Applicability::MachineApplicable,
);
}
.saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))),
_ => nbits,
},
- ExprKind::MethodCall(method, [left, right], _) => {
+ ExprKind::MethodCall(method, left, [right], _) => {
if signed {
return nbits;
}
};
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
},
- ExprKind::MethodCall(method, [_, lo, hi], _) => {
+ ExprKind::MethodCall(method, _, [lo, hi], _) => {
if method.ident.as_str() == "clamp" {
//FIXME: make this a diagnostic item
if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
}
nbits
},
- ExprKind::MethodCall(method, [_value], _) => {
+ ExprKind::MethodCall(method, _value, [], _) => {
if method.ident.name.as_str() == "signum" {
0 // do not lint if cast comes from a `signum` function
} else {
cx.typeck_results().expr_ty(expr),
);
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
- } else if let ExprKind::MethodCall(method_path, [self_arg, ..], _) = &expr.kind {
+ } else if let ExprKind::MethodCall(method_path, self_arg, ..) = &expr.kind {
if method_path.ident.name == sym!(cast)
&& let Some(generic_args) = method_path.args
&& let [GenericArg::Type(cast_to)] = generic_args.args
return false;
};
match parent.kind {
- ExprKind::MethodCall(name, [self_arg, ..], _) if self_arg.hir_id == e.hir_id => {
+ ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => {
if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
&& let Some(def_id) = cx.tcx.impl_of_method(def_id)
}
// Don't lint for the result of methods that always return non-negative values.
- if let ExprKind::MethodCall(path, _, _) = cast_op.kind {
+ if let ExprKind::MethodCall(path, ..) = cast_op.kind {
let mut method_name = path.ident.name.as_str();
let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
if_chain! {
if method_name == "unwrap";
if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]);
- if let ExprKind::MethodCall(inner_path, _, _) = &arglist[0][0].kind;
+ if let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind;
then {
method_name = inner_path.ident.name.as_str();
}
impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
fn new(cx: &'a LateContext<'tcx>) -> Self {
- Self {
- ty_bounds: vec![TyBound::Nothing],
- cx,
- }
+ Self { ty_bounds: vec![TyBound::Nothing], cx }
}
/// Check whether a passed literal has potential to cause fallback or not.
}
return;
}
- },
+ }
- ExprKind::MethodCall(_, args, _) => {
+ ExprKind::MethodCall(_, receiver, args, _) => {
if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
- for (expr, bound) in iter::zip(*args, fn_sig.inputs()) {
+ for (expr, bound) in
+ iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs())
+ {
self.ty_bounds.push(TyBound::Ty(*bound));
self.visit_expr(expr);
self.ty_bounds.pop();
}
return;
}
- },
+ }
ExprKind::Struct(_, fields, base) => {
let ty = self.cx.typeck_results().expr_ty(expr);
return;
}
}
- },
+ }
ExprKind::Lit(lit) => {
let ty = self.cx.typeck_results().expr_ty(expr);
self.check_lit(lit, ty, expr.hir_id);
return;
- },
+ }
- _ => {},
+ _ => {}
}
walk_expr(self, expr);
} else {
self.ty_bounds.push(TyBound::Nothing);
}
- },
+ }
_ => self.ty_bounds.push(TyBound::Nothing),
}
}
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
- if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
+ if let PatKind::Binding(BindingAnnotation::REF, id, name, _) = pat.kind {
if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
// This binding id has been seen before. Add this pattern to the list of changes.
if let Some(prev_pat) = opt_prev_pat {
expr: &'tcx Expr<'_>,
) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
let (def_id, arg) = match expr.kind {
- ExprKind::MethodCall(_, [arg], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
+ ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
ExprKind::Call(
Expr {
kind: ExprKind::Path(path),
},
})
}),
- ExprKind::MethodCall(_, args, _) => {
+ ExprKind::MethodCall(_, receiver, args, _) => {
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
- args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
- if i == 0 {
- // Check for calls to trait methods where the trait is implemented on a reference.
- // Two cases need to be handled:
- // * `self` methods on `&T` will never have auto-borrow
- // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
- // priority.
- if e.hir_id != child_id {
- Position::ReborrowStable(precedence)
- } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
- && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
- && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
- && let subs = match cx
- .typeck_results()
- .node_substs_opt(parent.hir_id)
- .and_then(|subs| subs.get(1..))
- {
- Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
- None => cx.tcx.mk_substs(std::iter::empty::<ty::subst::GenericArg<'_>>()),
- } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
- // Trait methods taking `&self`
- sub_ty
- } else {
- // Trait methods taking `self`
- arg_ty
- } && impl_ty.is_ref()
- && cx.tcx.infer_ctxt().enter(|infcx|
- infcx
- .type_implements_trait(trait_id, impl_ty, subs, cx.param_env)
- .must_apply_modulo_regions()
- )
+ if receiver.hir_id == child_id {
+ // Check for calls to trait methods where the trait is implemented on a reference.
+ // Two cases need to be handled:
+ // * `self` methods on `&T` will never have auto-borrow
+ // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
+ // priority.
+ if e.hir_id != child_id {
+ return Some(Position::ReborrowStable(precedence))
+ } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
+ && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
+ && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
+ && let subs = match cx
+ .typeck_results()
+ .node_substs_opt(parent.hir_id)
+ .and_then(|subs| subs.get(1..))
{
- Position::MethodReceiverRefImpl
+ Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
+ None => cx.tcx.mk_substs(std::iter::empty::<ty::subst::GenericArg<'_>>()),
+ } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
+ // Trait methods taking `&self`
+ sub_ty
} else {
- Position::MethodReceiver
- }
+ // Trait methods taking `self`
+ arg_ty
+ } && impl_ty.is_ref()
+ && cx.tcx.infer_ctxt().enter(|infcx|
+ infcx
+ .type_implements_trait(trait_id, impl_ty, subs, cx.param_env)
+ .must_apply_modulo_regions()
+ )
+ {
+ return Some(Position::MethodReceiverRefImpl)
} else {
- let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
+ return Some(Position::MethodReceiver)
+ }
+ }
+ args.iter()
+ .position(|arg| arg.hir_id == child_id)
+ .map(|i| {
+ let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
if let ty::Param(param_ty) = ty.kind() {
- needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv)
+ needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv)
} else {
ty_auto_deref_stability(
cx,
- cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
+ cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
precedence,
)
.position_for_arg()
}
- }
- })
+ })
},
ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
- let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+ let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
{
match expr.kind {
ExprKind::MethodCall(
_,
+ map,
[
- map,
Expr {
kind: ExprKind::AddrOf(_, _, key),
span: key_span,
value: &'tcx Expr<'tcx>,
}
fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
- if let ExprKind::MethodCall(_, [map, key, value], _) = expr.kind {
+ if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind {
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) {
Some(InsertExpr { map, key, value })
if !is_adjusted(cx, &body.value);
if let ExprKind::Call(callee, args) = body.value.kind;
if let ExprKind::Path(_) = callee.kind;
- if check_inputs(cx, body.params, args);
+ if check_inputs(cx, body.params, None, args);
let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
.map_or(callee_ty, |id| cx.tcx.type_of(id));
if_chain!(
if !is_adjusted(cx, &body.value);
- if let ExprKind::MethodCall(path, args, _) = body.value.kind;
- if check_inputs(cx, body.params, args);
+ if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
+ if check_inputs(cx, body.params, Some(receiver), args);
let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
let substs = cx.typeck_results().node_substs(body.value.hir_id);
let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs);
}
}
-fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool {
- if params.len() != call_args.len() {
+fn check_inputs(
+ cx: &LateContext<'_>,
+ params: &[Param<'_>],
+ receiver: Option<&Expr<'_>>,
+ call_args: &[Expr<'_>],
+) -> bool {
+ if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) {
return false;
}
let binding_modes = cx.typeck_results().pat_binding_modes();
- std::iter::zip(params, call_args).all(|(param, arg)| {
+ let check_inputs = |param: &Param<'_>, arg| {
match param.pat.kind {
PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
_ => return false,
},
_ => false,
}
- })
+ };
+ std::iter::zip(params, receiver.into_iter().chain(call_args.iter()))
+ .all(|(param, arg)| check_inputs(param, arg))
}
fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
// match call to unwrap
- if let ExprKind::MethodCall(unwrap_fun, [write_call], _) = expr.kind;
+ if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind;
if unwrap_fun.ident.name == sym::unwrap;
// match call to write_fmt
- if let ExprKind::MethodCall(write_fun, [write_recv, write_arg], _) = look_in_block(cx, &write_call.kind);
+ if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind);
if write_fun.ident.name == sym!(write_fmt);
// match calls to std::io::stdout() / std::io::stderr ()
if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
if let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res);
// Find id of the local we found in the block
- if let PatKind::Binding(BindingAnnotation::Unannotated, local_hir_id, _ident, None) = local.pat.kind;
+ if let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind;
// If those two are the same hir id
if res_pat.hir_id == local_hir_id;
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
- let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+ let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
{
suggestion.maybe_par()
}
-fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
- if let Some(method) = get_specialized_log_method(cx, &args[1]) {
+fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
+ if let Some(method) = get_specialized_log_method(cx, &args[0]) {
span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
expr.span,
"logarithm for bases 2, 10 and e can be computed more accurately",
"consider using",
- format!("{}.{}()", Sugg::hir(cx, &args[0], "..").maybe_par(), method),
+ format!("{}.{}()", Sugg::hir(cx, receiver, "..").maybe_par(), method),
Applicability::MachineApplicable,
);
}
// TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and
// suggest usage of `(x + (y - 1)).ln_1p()` instead
-fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
+fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
},
lhs,
rhs,
- ) = &args[0].kind
+ ) = receiver.kind
{
let recv = match (
constant(cx, cx.typeck_results(), lhs),
}
}
-fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
+fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
// Check receiver
- if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
+ if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) {
let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
"exp"
} else if F32(2.0) == value || F64(2.0) == value {
expr.span,
"exponent for bases 2 and e can be computed more accurately",
"consider using",
- format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method),
+ format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method),
Applicability::MachineApplicable,
);
}
// Check argument
- if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
+ if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
(
SUBOPTIMAL_FLOPS,
"square-root of a number can be computed more efficiently and accurately",
- format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
+ format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
)
} else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
(
IMPRECISE_FLOPS,
"cube-root of a number can be computed more accurately",
- format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
+ format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
)
} else if let Some(exponent) = get_integer_from_float_constant(&value) {
(
"exponentiation with integer powers can be computed more efficiently",
format!(
"{}.powi({})",
- Sugg::hir(cx, &args[0], "..").maybe_par(),
+ Sugg::hir(cx, receiver, "..").maybe_par(),
numeric_literal::format(&exponent.to_string(), None, false)
),
)
}
}
-fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
- if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
+fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
+ if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
if value == Int(2) {
if let Some(parent) = get_parent_expr(cx, expr) {
if let Some(grandparent) = get_parent_expr(cx, parent) {
- if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = grandparent.kind {
- if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
+ if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind
+ {
+ if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
return;
}
}
"consider using",
format!(
"{}.mul_add({}, {})",
- Sugg::hir(cx, &args[0], "..").maybe_par(),
- Sugg::hir(cx, &args[0], ".."),
+ Sugg::hir(cx, receiver, "..").maybe_par(),
+ Sugg::hir(cx, receiver, ".."),
Sugg::hir(cx, other_addend, ".."),
),
Applicability::MachineApplicable,
}
}
-fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
+fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
},
add_lhs,
add_rhs,
- ) = args[0].kind
+ ) = receiver.kind
{
// check if expression of the form x * x + y * y
if_chain! {
if_chain! {
if let ExprKind::MethodCall(
PathSegment { ident: lmethod_name, .. },
- [largs_0, largs_1, ..],
+ largs_0, [largs_1, ..],
_
) = &add_lhs.kind;
if let ExprKind::MethodCall(
PathSegment { ident: rmethod_name, .. },
- [rargs_0, rargs_1, ..],
+ rargs_0, [rargs_1, ..],
_
) = &add_rhs.kind;
if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
None
}
-fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
- if let Some(message) = detect_hypot(cx, args) {
+fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
+ if let Some(message) = detect_hypot(cx, receiver) {
span_lint_and_sugg(
cx,
IMPRECISE_FLOPS,
if cx.typeck_results().expr_ty(lhs).is_floating_point();
if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs);
if F32(1.0) == value || F64(1.0) == value;
- if let ExprKind::MethodCall(path, [self_arg, ..], _) = &lhs.kind;
+ if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind;
if cx.typeck_results().expr_ty(self_arg).is_floating_point();
if path.ident.name.as_str() == "exp";
then {
) = &expr.kind
{
if let Some(parent) = get_parent_expr(cx, expr) {
- if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = parent.kind {
- if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
+ if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind {
+ if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
return;
}
}
fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
if_chain! {
- if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, args_a, _) = expr_a.kind;
- if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, args_b, _) = expr_b.kind;
+ if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind;
+ if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind;
then {
return method_name_a.as_str() == method_name_b.as_str() &&
args_a.len() == args_b.len() &&
(
["ln", "log2", "log10"].contains(&method_name_a.as_str()) ||
- method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1])
+ method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])
);
}
}
rhs,
) = &expr.kind;
if are_same_base_logs(cx, lhs, rhs);
- if let ExprKind::MethodCall(_, [largs_self, ..], _) = &lhs.kind;
- if let ExprKind::MethodCall(_, [rargs_self, ..], _) = &rhs.kind;
+ if let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind;
+ if let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind;
then {
span_lint_and_sugg(
cx,
return;
}
- if let ExprKind::MethodCall(path, args, _) = &expr.kind {
- let recv_ty = cx.typeck_results().expr_ty(&args[0]);
+ if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
+ let recv_ty = cx.typeck_results().expr_ty(receiver);
if recv_ty.is_floating_point() {
match path.ident.name.as_str() {
- "ln" => check_ln1p(cx, expr, args),
- "log" => check_log_base(cx, expr, args),
- "powf" => check_powf(cx, expr, args),
- "powi" => check_powi(cx, expr, args),
- "sqrt" => check_hypot(cx, expr, args),
+ "ln" => check_ln1p(cx, expr, receiver),
+ "log" => check_log_base(cx, expr, receiver, args),
+ "powf" => check_powf(cx, expr, receiver, args),
+ "powi" => check_powi(cx, expr, receiver, args),
+ "sqrt" => check_hypot(cx, expr, receiver),
_ => {},
}
}
}
}
-fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) {
+fn check_format_in_format_args(
+ cx: &LateContext<'_>,
+ call_site: Span,
+ name: Symbol,
+ arg: &Expr<'_>,
+) {
let expn_data = arg.span.ctxt().outer_expn_data();
if expn_data.call_site.from_expansion() {
return;
fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
if_chain! {
if !value.span.from_expansion();
- if let ExprKind::MethodCall(_, [receiver], _) = value.kind;
+ 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);
// Returns true if `hir_id` is referred to by multiple format params
fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool {
- args.params()
- .filter(|param| param.value.hir_id == hir_id)
- .at_most_one()
- .is_err()
+ args.params().filter(|param| param.value.hir_id == hir_id).at_most_one().is_err()
}
fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
let mut n_total = 0;
let mut n_needed = 0;
loop {
- if let Some(Adjustment {
- kind: Adjust::Deref(overloaded_deref),
- target,
- }) = iter.next()
- {
+ if let Some(Adjustment { kind: Adjust::Deref(overloaded_deref), target }) = iter.next() {
n_total += 1;
if overloaded_deref.is_some() {
n_needed = n_total;
fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
// Get the hir_id of the object we are calling the method on
- if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind;
+ if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind;
// Is the method to_string() ?
if path.ident.name == sym::to_string;
// Is the method a part of the ToString trait? (i.e. not to_string() implemented
impl<'tcx> LateLintPass<'tcx> for FormatPushString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let arg = match expr.kind {
- ExprKind::MethodCall(_, [_, arg], _) => {
+ ExprKind::MethodCall(_, _, [arg], _) => {
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) &&
match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
arg
return;
}
match expr.kind {
- Call(_, args) | MethodCall(_, args, _) => {
+ Call(_, args) => {
let mut tys = DefIdSet::default();
for arg in args {
if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
tys.clear();
}
},
+ MethodCall(_, receiver, args, _) => {
+ let mut tys = DefIdSet::default();
+ for arg in std::iter::once(receiver).chain(args.iter()) {
+ if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
+ && is_mutable_ty(
+ self.cx,
+ self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg),
+ arg.span,
+ &mut tys,
+ )
+ && is_mutated_static(arg)
+ {
+ self.mutates_static = true;
+ return;
+ }
+ tys.clear();
+ }
+ },
Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
self.mutates_static |= is_mutated_static(target);
},
}
}
},
- hir::ExprKind::MethodCall(_, args, _) => {
+ hir::ExprKind::MethodCall(_, receiver, args, _) => {
let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap();
let base_type = self.cx.tcx.type_of(def_id);
if type_is_unsafe_function(self.cx, base_type) {
+ self.check_arg(receiver);
for arg in args {
self.check_arg(arg);
}
fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
if_chain! {
- if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+ if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
if path.ident.as_str() == "lock";
let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
if is_type_diagnostic_item(cx, ty, sym::Mutex);
let mut removed_pat: FxHashSet<hir::HirId> = FxHashSet::default();
let mut slices: FxIndexMap<hir::HirId, SliceLintInformation> = FxIndexMap::default();
pat.walk_always(|pat| {
- if let hir::PatKind::Binding(binding, value_hir_id, ident, sub_pat) = pat.kind {
- // We'll just ignore mut and ref mut for simplicity sake right now
- if let hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut = binding {
- return;
- }
-
+ // We'll just ignore mut and ref mut for simplicity sake right now
+ if let hir::PatKind::Binding(
+ hir::BindingAnnotation(by_ref, hir::Mutability::Not),
+ value_hir_id,
+ ident,
+ sub_pat,
+ ) = pat.kind
+ {
// This block catches bindings with sub patterns. It would be hard to build a correct suggestion
// for them and it's likely that the user knows what they are doing in such a case.
if removed_pat.contains(&value_hir_id) {
if let ty::Slice(inner_ty) | ty::Array(inner_ty, _) = bound_ty.peel_refs().kind() {
// The values need to use the `ref` keyword if they can't be copied.
// This will need to be adjusted if the lint want to support mutable access in the future
- let src_is_ref = bound_ty.is_ref() && binding != hir::BindingAnnotation::Ref;
+ let src_is_ref = bound_ty.is_ref() && by_ref != hir::ByRef::Yes;
let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty));
let slice_info = slices
MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"),
Finite => {
return;
- },
+ }
};
span_lint(cx, lint, expr.span, msg);
}
/// is an upper bound, e.g., some methods can return a possibly
/// infinite iterator at worst, e.g., `take_while`.
const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [
- ("zip", 2, All, Infinite),
- ("chain", 2, Any, Infinite),
- ("cycle", 1, Always, Infinite),
- ("map", 2, First, Infinite),
- ("by_ref", 1, First, Infinite),
- ("cloned", 1, First, Infinite),
- ("rev", 1, First, Infinite),
- ("inspect", 1, First, Infinite),
- ("enumerate", 1, First, Infinite),
- ("peekable", 2, First, Infinite),
- ("fuse", 1, First, Infinite),
- ("skip", 2, First, Infinite),
- ("skip_while", 1, First, Infinite),
- ("filter", 2, First, Infinite),
- ("filter_map", 2, First, Infinite),
- ("flat_map", 2, First, Infinite),
- ("unzip", 1, First, Infinite),
- ("take_while", 2, First, MaybeInfinite),
- ("scan", 3, First, MaybeInfinite),
+ ("zip", 1, All, Infinite),
+ ("chain", 1, Any, Infinite),
+ ("cycle", 0, Always, Infinite),
+ ("map", 1, First, Infinite),
+ ("by_ref", 0, First, Infinite),
+ ("cloned", 0, First, Infinite),
+ ("rev", 0, First, Infinite),
+ ("inspect", 0, First, Infinite),
+ ("enumerate", 0, First, Infinite),
+ ("peekable", 1, First, Infinite),
+ ("fuse", 0, First, Infinite),
+ ("skip", 1, First, Infinite),
+ ("skip_while", 0, First, Infinite),
+ ("filter", 1, First, Infinite),
+ ("filter_map", 1, First, Infinite),
+ ("flat_map", 1, First, Infinite),
+ ("unzip", 0, First, Infinite),
+ ("take_while", 1, First, MaybeInfinite),
+ ("scan", 2, First, MaybeInfinite),
];
fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
match expr.kind {
- ExprKind::MethodCall(method, args, _) => {
+ ExprKind::MethodCall(method, receiver, args, _) => {
for &(name, len, heuristic, cap) in &HEURISTICS {
if method.ident.name.as_str() == name && args.len() == len {
return (match heuristic {
Always => Infinite,
- First => is_infinite(cx, &args[0]),
- Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])),
- All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])),
+ First => is_infinite(cx, receiver),
+ Any => is_infinite(cx, receiver).or(is_infinite(cx, &args[0])),
+ All => is_infinite(cx, receiver).and(is_infinite(cx, &args[0])),
})
.and(cap);
}
}
- if method.ident.name == sym!(flat_map) && args.len() == 2 {
- if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind {
+ if method.ident.name == sym!(flat_map) && args.len() == 1 {
+ if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
let body = cx.tcx.hir().body(body);
return is_infinite(cx, &body.value);
}
/// the names and argument lengths of methods that *may* exhaust their
/// iterators
const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [
- ("find", 2),
- ("rfind", 2),
- ("position", 2),
- ("rposition", 2),
- ("any", 2),
- ("all", 2),
+ ("find", 1),
+ ("rfind", 1),
+ ("position", 1),
+ ("rposition", 1),
+ ("any", 1),
+ ("all", 1),
];
/// the names and argument lengths of methods that *always* exhaust
/// their iterators
const COMPLETING_METHODS: [(&str, usize); 12] = [
- ("count", 1),
- ("fold", 3),
- ("for_each", 2),
- ("partition", 2),
- ("max", 1),
- ("max_by", 2),
- ("max_by_key", 2),
- ("min", 1),
- ("min_by", 2),
- ("min_by_key", 2),
- ("sum", 1),
- ("product", 1),
+ ("count", 0),
+ ("fold", 2),
+ ("for_each", 1),
+ ("partition", 1),
+ ("max", 0),
+ ("max_by", 1),
+ ("max_by_key", 1),
+ ("min", 0),
+ ("min_by", 1),
+ ("min_by_key", 1),
+ ("sum", 0),
+ ("product", 0),
];
/// the paths of types that are known to be infinitely allocating
fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
match expr.kind {
- ExprKind::MethodCall(method, args, _) => {
+ ExprKind::MethodCall(method, receiver, args, _) => {
for &(name, len) in &COMPLETING_METHODS {
if method.ident.name.as_str() == name && args.len() == len {
- return is_infinite(cx, &args[0]);
+ return is_infinite(cx, receiver);
}
}
for &(name, len) in &POSSIBLY_COMPLETING_METHODS {
if method.ident.name.as_str() == name && args.len() == len {
- return MaybeInfinite.and(is_infinite(cx, &args[0]));
+ return MaybeInfinite.and(is_infinite(cx, receiver));
}
}
- if method.ident.name == sym!(last) && args.len() == 1 {
- let not_double_ended = cx
- .tcx
- .get_diagnostic_item(sym::DoubleEndedIterator)
- .map_or(false, |id| {
- !implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[])
+ if method.ident.name == sym!(last) && args.is_empty() {
+ let not_double_ended =
+ cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator).map_or(false, |id| {
+ !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[])
});
if not_double_ended {
- return is_infinite(cx, &args[0]);
+ return is_infinite(cx, receiver);
}
} else if method.ident.name == sym!(collect) {
let ty = cx.typeck_results().expr_ty(expr);
.iter()
.any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item))
{
- return is_infinite(cx, &args[0]);
+ return is_infinite(cx, receiver);
}
}
},
}
fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
- if let (&ExprKind::MethodCall(method_path, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
+ if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
// check if we are in an is_empty() method
if let Some(name) = get_item_name(cx, method) {
if name.as_str() == "is_empty" {
}
}
- check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
+ check_len(cx, span, method_path.ident.name, receiver, args, &lit.node, op, compare_to);
} else {
check_empty_expr(cx, span, method, lit, op);
}
cx: &LateContext<'_>,
span: Span,
method_name: Symbol,
+ receiver: &Expr<'_>,
args: &[Expr<'_>],
lit: &LitKind,
op: &str,
return;
}
- if method_name == sym::len && args.len() == 1 && has_is_empty(cx, &args[0]) {
+ if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
format!(
"{}{}.is_empty()",
op,
- snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
+ snippet_with_applicability(cx, receiver.span, "_", &mut applicability)
),
applicability,
);
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
-use rustc_hir::BindingAnnotation;
+use rustc_hir::{BindingAnnotation, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
};
let mutability = match mode {
- BindingAnnotation::RefMut | BindingAnnotation::Mutable => "<mut> ",
+ BindingAnnotation(_, Mutability::Mut) => "<mut> ",
_ => "",
};
hir_id = None;
return;
}
- if let BindingAnnotation::Unannotated = annotation {
+ if let BindingAnnotation::NONE = annotation {
hir_id = Some(id);
}
});
let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
if_chain! {
- if let ExprKind::MethodCall(method, [recv], _) = end.kind;
+ if let ExprKind::MethodCall(method, recv, [], _) = end.kind;
if method.ident.name == sym::len;
if path_to_local(recv) == path_to_local(base);
then {
fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
if_chain! {
- if let ExprKind::MethodCall(method, [arg], _) = expr.kind;
+ if let ExprKind::MethodCall(method, arg, [], _) = expr.kind;
if method.ident.name == sym::clone;
then { arg } else { expr }
}
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
if_chain! {
if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind;
- if let ExprKind::MethodCall(method, [callee, ..], _) = unpack_cond(cond).kind;
+ if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind;
if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name);
if let ty::Adt(def, _substs) = cx.typeck_results().expr_ty(callee).kind();
if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did());
fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
- if let ExprKind::MethodCall(method, [self_arg], _) = arg.kind {
+ if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
let method_name = method.ident.as_str();
// check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
match method_name {
if_chain! {
if let Some(hir_id) = path_to_local(bound);
if let Node::Pat(pat) = cx.tcx.hir().get(hir_id);
- if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind;
+ if let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind;
then {
return Some(hir_id);
}
}
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
if_chain! {
- if let ExprKind::MethodCall(method, args, _) = expr.kind;
- if let ExprKind::MethodCall(chain_method, _, _) = args[0].kind;
- if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
+ if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind;
+ if let ExprKind::MethodCall(chain_method, ..) = receiver.kind;
+ if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator);
then {
- let ty = cx.typeck_results().expr_ty(&args[0]);
+ let ty = cx.typeck_results().expr_ty(receiver);
let mut applicability = Applicability::MaybeIncorrect;
let is_empty_sugg = "next().is_none()".to_string();
let method_name = method.ident.name.as_str();
"len" => "count()".to_string(),
"is_empty" => is_empty_sugg,
"contains" => {
- let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability);
+ let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability);
let (arg, pred) = contains_arg
.strip_prefix('&')
.map_or(("&x", &*contains_arg), |s| ("x", s));
if let StmtKind::Local(local) = stmt.kind;
if let PatKind::Binding(_, id, ..) = local.pat.kind;
if let Some(init_expr) = local.init;
- if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind;
+ if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind;
if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
let ty = cx.typeck_results().expr_ty(init_expr);
if is_type_diagnostic_item(cx, ty, sym::Vec) ||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
// Check function calls on our collection
- if let ExprKind::MethodCall(method_name, [recv, args @ ..], _) = &expr.kind {
+ if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind {
if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
self.visit_expr(recv);
fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
if_chain! {
- if let ExprKind::MethodCall(method, [recv], _) = expr.kind;
+ if let ExprKind::MethodCall(method, recv, [], _) = expr.kind;
if method.ident.name == sym::len;
if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind;
if path.segments.len() == 1;
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if_chain! {
// a range index op
- if let ExprKind::MethodCall(meth, [args_0, args_1, ..], _) = &expr.kind;
+ if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind;
if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX))
|| (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT));
if !self.check(args_1, args_0, expr);
self.visit_expr(expr);
}
},
- ExprKind::MethodCall(_, args, _) => {
+ ExprKind::MethodCall(_, receiver, args, _) => {
let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
- for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) {
+ for (ty, expr) in iter::zip(
+ self.cx.tcx.fn_sig(def_id).inputs().skip_binder(),
+ std::iter::once(receiver).chain(args.iter()),
+ ) {
self.prefer_mutable = false;
if let ty::Ref(_, _, mutbl) = *ty.kind() {
if mutbl == Mutability::Mut {
| ExprKind::Repeat(e, _)
| ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
- ExprKind::Array(es) | ExprKind::MethodCall(_, es, _) | ExprKind::Tup(es) => {
- never_loop_expr_all(&mut es.iter(), main_loop_id)
+ ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id),
+ ExprKind::MethodCall(_, receiver, es, _) => {
+ never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id)
},
ExprKind::Struct(_, fields, base) => {
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id);
InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
never_loop_expr(expr, main_loop_id)
},
- InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter(), main_loop_id),
+ InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter().copied(), main_loop_id),
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
- never_loop_expr_all(&mut once(in_expr).chain(out_expr.iter()), main_loop_id)
+ never_loop_expr_all(&mut once(*in_expr).chain(out_expr.iter().copied()), main_loop_id)
},
InlineAsmOperand::Const { .. }
| InlineAsmOperand::SymFn { .. }
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
use std::iter::Iterator;
if_chain! {
if let Node::Pat(pat) = node;
if let PatKind::Binding(bind_ann, ..) = pat.kind;
- if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
+ if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut));
let parent_node = cx.tcx.hir().get_parent_node(hir_id);
if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
if let Some(init) = parent_let_expr.init;
if_chain! {
// Extract method being called
if let StmtKind::Semi(semi_stmt) = &stmt.kind;
- if let ExprKind::MethodCall(path, args, _) = &semi_stmt.kind;
+ if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
// Figure out the parameters for the method call
- if let Some(self_expr) = args.get(0);
- if let Some(pushed_item) = args.get(1);
+ if let Some(pushed_item) = args.get(0);
// Check that the method being called is push() on a Vec
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
if path.ident.name.as_str() == "push";
) => (arg, "&mut "),
ExprKind::MethodCall(
method,
- [
- Expr {
- kind: ExprKind::Array([arg]),
- ..
- },
- ],
+ Expr {
+ kind: ExprKind::Array([arg]),
+ ..
+ },
+ [],
_,
) if method.ident.name == rustc_span::sym::iter => (arg, "&"),
ExprKind::MethodCall(
method,
- [
- Expr {
- kind: ExprKind::Array([arg]),
- ..
- },
- ],
+ Expr {
+ kind: ExprKind::Array([arg]),
+ ..
+ },
+ [],
_,
) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
ExprKind::MethodCall(
method,
- [
- Expr {
- kind: ExprKind::Array([arg]),
- ..
- },
- ],
+ Expr {
+ kind: ExprKind::Array([arg]),
+ ..
+ },
+ [],
_,
) if method.ident.name == rustc_span::sym::into_iter => (arg, ""),
// Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise.
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) {
([stmt, stmts @ ..], expr) => {
- if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind {
+ if let StmtKind::Local(&Local {
+ init: Some(e),
+ els: None,
+ ..
+ })
+ | StmtKind::Semi(e)
+ | StmtKind::Expr(e) = stmt.kind
+ {
(e, !stmts.is_empty() || expr.is_some())
} else {
return;
if let Res::Def(_, pat_did) = pat_path.res;
if match_def_path(cx, pat_did, &paths::OPTION_SOME);
// check for call to `Iterator::next`
- if let ExprKind::MethodCall(method_name, [iter_expr], _) = let_expr.kind;
+ if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind;
if method_name.ident.name == sym::next;
if is_trait_method(cx, let_expr, sym::Iterator);
if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr);
if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);
then {
- cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (real_ty, resolved_ty))
+ cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty))
} else {
None
}
fn is_ty_conversion(expr: &Expr<'_>) -> bool {
if let ExprKind::Cast(..) = expr.kind {
true
- } else if let ExprKind::MethodCall(path, [_], _) = expr.kind
+ } else if let ExprKind::MethodCall(path, _, [], _) = expr.kind
&& path.ident.name == rustc_span::sym::try_into
{
// This is only called for `usize` which implements `TryInto`. Therefore,
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if let Some(parent_expr) = get_parent_expr(cx, expr)
&& let Assign(left_expr, collect_expr, _) = &parent_expr.kind
- && let hir::ExprKind::MethodCall(seg, _, _) = &collect_expr.kind
+ && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
&& seg.args.is_none()
- && let hir::ExprKind::MethodCall(_, [target_expr], _) = &collect_expr.kind
+ && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
&& let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
&& match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv);
target_expr: &hir::Expr<'_>,
msrv: Option<RustcVersion>,
) {
- if let hir::ExprKind::MethodCall(_, [into_iter_expr, _], _) = &target_expr.kind
+ if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
- && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &into_iter_expr.kind
+ && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind
&& let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
&& match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER)
&& match_acceptable_type(cx, left_expr, msrv)
target_expr: &hir::Expr<'_>,
msrv: Option<RustcVersion>,
) {
- if let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
+ if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED)
|| match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED))
- && let hir::ExprKind::MethodCall(_, [iter_expr, _], _) = &filter_expr.kind
+ && let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
- && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &iter_expr.kind
+ && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &iter_expr.kind
&& let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id)
&& match_acceptable_def_path(cx, iter_expr_def_id)
&& match_acceptable_type(cx, left_expr, msrv)
msrv: Option<RustcVersion>,
) {
if meets_msrv(msrv, msrvs::STRING_RETAIN)
- && let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
+ && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
- && let hir::ExprKind::MethodCall(_, [chars_expr, _], _) = &filter_expr.kind
+ && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
- && let hir::ExprKind::MethodCall(_, [str_expr], _) = &chars_expr.kind
+ && let hir::ExprKind::MethodCall(_, str_expr, [], _) = &chars_expr.kind
&& let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
&& match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
&& let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
}
fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
- if let hir::ExprKind::MethodCall(_, [_, closure], _) = filter_expr.kind
+ if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind
&& let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind
&& let filter_body = cx.tcx.hir().body(body)
&& let [filter_params] = filter_body.params
ExprKind::Call(func, args) => {
parse_call(cx, expr.span, func, args);
},
- ExprKind::MethodCall(path_segment, args, _) => {
- parse_method_call(cx, expr.span, path_segment, args);
+ ExprKind::MethodCall(path_segment, receiver, ..) => {
+ parse_method_call(cx, expr.span, path_segment, receiver);
},
_ => (),
}
}
/// Tries to parse an expression as a method call, emitting the warning if necessary.
-fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, args: &[Expr<'_>]) {
- if args.is_empty() {
- // When parsing TryFrom::try_from(...).expect(...), we will have more than 1 arg.
- return;
- }
-
+fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, receiver: &Expr<'_>) {
let ident = path_segment.ident.as_str();
- let method_arg_kind = &args[0].kind;
+ let method_arg_kind = &receiver.kind;
if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) {
warn_then_suggest(cx, span);
} else if let ExprKind::Call(func, args) = method_arg_kind {
if_chain! {
if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
- if let ExprKind::MethodCall(_, [target_arg, pattern], _) = cond.kind;
+ if let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind;
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id);
if let ExprKind::Path(target_path) = &target_arg.kind;
then {
// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
if_chain! {
- if let ExprKind::MethodCall(_, [arg], _) = expr.kind;
+ if let ExprKind::MethodCall(_, arg, [], _) = expr.kind;
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if match_def_path(cx, method_def_id, &paths::STR_LEN);
then {
)
}
-fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
- let var_arg = &map_args[0];
+fn lint_map_unit_fn(
+ cx: &LateContext<'_>,
+ stmt: &hir::Stmt<'_>,
+ expr: &hir::Expr<'_>,
+ map_args: (&hir::Expr<'_>, &[hir::Expr<'_>]),
+) {
+ let var_arg = &map_args.0;
let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
("Option", "Some", OPTION_MAP_UNIT_FN)
} else {
return;
};
- let fn_arg = &map_args[1];
+ let fn_arg = &map_args.1[0];
if is_unit_function(cx, fn_arg) {
let mut applicability = Applicability::MachineApplicable;
};
if_chain! {
- if let ExprKind::MethodCall(ok_path, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
+ if let ExprKind::MethodCall(ok_path, result_types_0, ..) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation
if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized;
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
}
// `ref` and `ref mut` annotations were handled earlier.
- let annotation = if matches!(annotation, BindingAnnotation::Mutable) {
+ let annotation = if matches!(annotation, BindingAnnotation::MUT) {
"mut "
} else {
""
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{is_lang_ctor, peel_blocks};
use rustc_errors::Applicability;
-use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, LangItem, PatKind, QPath};
+use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty;
pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
- let arm_ref: Option<BindingAnnotation> = if is_none_arm(cx, &arms[0]) {
+ let arm_ref_mut = if is_none_arm(cx, &arms[0]) {
is_ref_some_arm(cx, &arms[1])
} else if is_none_arm(cx, &arms[1]) {
is_ref_some_arm(cx, &arms[0])
} else {
None
};
- if let Some(rb) = arm_ref {
- let suggestion = if rb == BindingAnnotation::Ref {
- "as_ref"
- } else {
- "as_mut"
+ if let Some(rb) = arm_ref_mut {
+ let suggestion = match rb {
+ Mutability::Not => "as_ref",
+ Mutability::Mut => "as_mut",
};
let output_ty = cx.typeck_results().expr_ty(expr);
}
// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
-fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotation> {
+fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
if_chain! {
if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
if is_lang_ctor(cx, qpath, LangItem::OptionSome);
- if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
- if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
+ if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind;
if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind;
if let ExprKind::Path(ref some_path) = e.kind;
if is_lang_ctor(cx, some_path, LangItem::OptionSome);
if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind;
if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
then {
- return Some(rb)
+ return Some(mutabl)
}
}
None
impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
match ex.kind {
- ExprKind::MethodCall(segment, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
+ ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
_ => walk_expr(self, ex),
}
}
};
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
+use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
use rustc_lint::LateContext;
use rustc_span::sym;
use rustc_typeck::hir_ty_to_ty;
},
)),
) => {
- return !matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut)
- && pat_ident.name == first_seg.ident.name;
+ return !matches!(annot, BindingAnnotation(ByRef::Yes, _)) && pat_ident.name == first_seg.ident.name;
},
// Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
(PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
// check that `while_let_on_iterator` lint does not trigger
if_chain! {
if keyword == "while";
- if let ExprKind::MethodCall(method_path, _, _) = let_expr.kind;
+ if let ExprKind::MethodCall(method_path, ..) = let_expr.kind;
if method_path.ident.name == sym::next;
if is_trait_method(cx, let_expr, sym::Iterator);
then {
self.is_chain_end = false;
match ex.kind {
- ExprKind::MethodCall(_, [ref expr, ..], _) => {
+ ExprKind::MethodCall(_, expr, ..) => {
self.visit_expr(expr);
}
ExprKind::Binary(_, left, right) => {
ExprKind::Index(..) |
ExprKind::Ret(..) |
ExprKind::Repeat(..) |
- ExprKind::Yield(..) |
- ExprKind::MethodCall(..) => walk_expr(self, ex),
+ ExprKind::Yield(..) => walk_expr(self, ex),
ExprKind::AddrOf(_, _, _) |
ExprKind::Block(_, _) |
ExprKind::Break(_, _) |
let p_ty = cx.typeck_results().pat_ty(p);
collect_pat_paths(acc, cx, p, p_ty);
}),
- PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::Unannotated, .., None) | PatKind::Path(_) => {
+ PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::NONE, .., None) | PatKind::Path(_) => {
acc.push(ty);
},
_ => {},
if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
if !is_local_used(cx, needle, arg_id);
then {
- let haystack = if let ExprKind::MethodCall(path, args, _) =
+ let haystack = if let ExprKind::MethodCall(path, receiver, [], _) =
filter_recv.kind {
let p = path.ident.name;
- if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
- &args[0]
+ if p == sym::iter || p == sym!(iter_mut) {
+ receiver
} else {
filter_recv
}
if Some(id) == cx.tcx.lang_items().option_some_variant();
then {
let mut applicability = Applicability::MachineApplicable;
- let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
+ let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0].0).peel_refs();
if *self_ty.kind() != ty::Str {
return false;
"like this",
format!("{}{}.{}({})",
if info.eq { "" } else { "!" },
- snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
+ snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
suggest,
snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
applicability,
"like this",
format!("{}{}.{}('{}')",
if info.eq { "" } else { "!" },
- snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
+ snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
suggest,
c.escape_default()),
applicability,
use clippy_utils::sugg;
use clippy_utils::ty::is_copy;
use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
+use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, adjustment::Adjust};
use rustc_span::symbol::{sym, Symbol};
/// Checks for the `CLONE_ON_COPY` lint.
#[allow(clippy::too_many_lines)]
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, args: &[Expr<'_>]) {
- let arg = match args {
- [arg] if method_name == sym::clone => arg,
- _ => return,
- };
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ method_name: Symbol,
+ receiver: &Expr<'_>,
+ args: &[Expr<'_>],
+) {
+ let arg = if method_name == sym::clone && args.is_empty() { receiver } else { return };
if cx
.typeck_results()
.type_dependent_def_id(expr.hir_id)
// &*x is a nop, &x.clone() is not
ExprKind::AddrOf(..) => return,
// (*x).func() is useless, x.clone().func() can work in case func borrows self
- ExprKind::MethodCall(_, [self_arg, ..], _)
+ ExprKind::MethodCall(_, self_arg, ..)
if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
{
return;
hir_callee.kind,
ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
),
- ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
+ ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true,
ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
| ExprKind::Field(..)
| ExprKind::Index(..) => true,
_ => false,
},
// local binding capturing a reference
- Some(Node::Local(l))
- if matches!(
- l.pat.kind,
- PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..)
- ) =>
- {
+ Some(Node::Local(l)) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => {
return;
},
_ => false,
use super::CLONE_ON_REF_PTR;
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
- if !(args.len() == 1 && method_name == sym::clone) {
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ expr: &hir::Expr<'_>,
+ method_name: Symbol,
+ receiver: &hir::Expr<'_>,
+ args: &[hir::Expr<'_>],
+) {
+ if !(args.is_empty() && method_name == sym::clone) {
return;
}
- let arg = &args[0];
- let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs();
+ let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
if let ty::Adt(_, subst) = obj_ty.kind() {
let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
return;
};
- let snippet = snippet_with_macro_callsite(cx, arg.span, "..");
+ let snippet = snippet_with_macro_callsite(cx, receiver.span, "..");
span_lint_and_sugg(
cx,
// If the parent node's `to` argument is the same as the `to` argument
// of the last replace call in the current chain, don't lint as it was already linted
if let Some(parent) = get_parent_expr(cx, expr)
- && let Some(("replace", [_, current_from, current_to], _)) = method_call(parent)
+ && let Some(("replace", _, [current_from, current_to], _)) = method_call(parent)
&& eq_expr_value(cx, to, current_to)
&& from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
{
let mut from_args = VecDeque::new();
let _: Option<()> = for_each_expr(expr, |e| {
- if let Some(("replace", [_, from, to], _)) = method_call(e) {
+ if let Some(("replace", _, [from, to], _)) = method_call(e) {
if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
methods.push_front(e);
from_args.push_front(from);
.collect();
let app = Applicability::MachineApplicable;
let earliest_replace_call = replace_methods.methods.front().unwrap();
- if let Some((_, [..], span_lo)) = method_call(earliest_replace_call) {
+ if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) {
span_lint_and_sugg(
cx,
COLLAPSIBLE_STR_REPLACE,
expr: &hir::Expr<'_>,
method_span: Span,
name: &str,
+ receiver: &'tcx hir::Expr<'tcx>,
args: &'tcx [hir::Expr<'tcx>],
) {
// Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
loop {
arg_root = match &arg_root.kind {
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
- hir::ExprKind::MethodCall(method_name, call_args, _) => {
- if call_args.len() == 1
- && (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref)
- && {
- let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
- let base_type = arg_type.peel_refs();
- *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
- }
- {
- &call_args[0]
+ hir::ExprKind::MethodCall(method_name, receiver, [], ..) => {
+ if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && {
+ let arg_type = cx.typeck_results().expr_ty(receiver);
+ let base_type = arg_type.peel_refs();
+ *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
+ } {
+ receiver
} else {
break;
}
}
}
- if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) {
+ if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) {
return;
}
- let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]);
+ let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver);
let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) {
"||"
} else if is_type_diagnostic_item(cx, receiver_type, sym::Result) {
return;
};
- let arg_root = get_arg_root(cx, &args[1]);
+ let arg_root = get_arg_root(cx, &args[0]);
let span_replace_word = method_span.with_hi(expr.span.hi());
if_chain! {
if is_type_diagnostic_item(cx, ty, sym::Vec);
//check source object
- if let ExprKind::MethodCall(src_method, [drain_vec, drain_arg], _) = &arg.kind;
+ if let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind;
if src_method.ident.as_str() == "drain";
let src_ty = cx.typeck_results().expr_ty(drain_vec);
//check if actual src type is mutable for code suggestion
let closure_expr = peel_blocks(&body.value);
let arg_id = body.params[0].pat.hir_id;
match closure_expr.kind {
- hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, args, _) => {
+ hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
if_chain! {
if ident.name == method_name;
- if let hir::ExprKind::Path(path) = &args[0].kind;
- if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id);
+ if let hir::ExprKind::Path(path) = &receiver.kind;
+ if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
then {
return arg_id == *local
}
};
// closure ends with is_some() or is_ok()
if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
- if let ExprKind::MethodCall(path, [filter_arg], _) = filter_body.value.kind;
+ if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
Some(false)
if let [map_param] = map_body.params;
if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
// closure ends with expect() or unwrap()
- if let ExprKind::MethodCall(seg, [map_arg, ..], _) = map_body.value.kind;
+ if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
// .filter(..).map(|y| f(y).copied().unwrap())
// ~~~~
let map_arg_peeled = match map_arg.kind {
- ExprKind::MethodCall(method, [original_arg], _) if acceptable_methods(method) => {
+ ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
original_arg
},
_ => map_arg,
) = arg.kind
// LHS of subtraction is "x.len()"
- && let ExprKind::MethodCall(lhs_path, [lhs_recv], _) = &lhs.kind
+ && let ExprKind::MethodCall(lhs_path, lhs_recv, [], _) = &lhs.kind
&& lhs_path.ident.name == sym::len
// RHS of subtraction is 1
use super::INEFFICIENT_TO_STRING;
/// Checks for the `INEFFICIENT_TO_STRING` lint
-pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
+pub fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &hir::Expr<'_>,
+ method_name: Symbol,
+ receiver: &hir::Expr<'_>,
+ args: &[hir::Expr<'_>],
+) {
if_chain! {
- if args.len() == 1 && method_name == sym::to_string;
+ if args.is_empty() && method_name == sym::to_string;
if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id);
- let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
+ let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver);
let self_ty = substs.type_at(0);
let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
if deref_count >= 1;
self_ty, deref_self_ty
));
let mut applicability = Applicability::MachineApplicable;
- let arg_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
+ let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability);
diag.span_suggestion(
expr.span,
"try dereferencing the receiver",
expr: &hir::Expr<'_>,
method_span: Span,
method_name: Symbol,
- args: &[hir::Expr<'_>],
+ receiver: &hir::Expr<'_>,
) {
- let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
+ let self_ty = cx.typeck_results().expr_ty_adjusted(receiver);
if_chain! {
if let ty::Ref(..) = self_ty.kind();
if method_name == sym::into_iter;
if let Some(id) = path_to_local(recv);
if let Node::Pat(pat) = cx.tcx.hir().get(id);
if let PatKind::Binding(ann, _, _, _) = pat.kind;
- if ann != BindingAnnotation::Mutable;
+ if ann != BindingAnnotation::MUT;
then {
application = Applicability::Unspecified;
diag.span_help(
&& range.end.map_or(true, |e| {
if range.limits == RangeLimits::HalfOpen
&& let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind
- && let ExprKind::MethodCall(name, [self_arg], _) = e.kind
+ && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind
&& name.ident.name == sym::len
&& let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
{
let closure_expr = peel_blocks(&closure_body.value);
match closure_body.params[0].pat.kind {
hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
- hir::BindingAnnotation::Unannotated, .., name, None
+ hir::BindingAnnotation::NONE, .., name, None
) = inner.kind {
if ident_eq(name, closure_expr) {
lint_explicit_closure(cx, e.span, recv.span, true, msrv);
}
},
- hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
+ hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => {
match closure_expr.kind {
hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
if ident_eq(name, inner) {
}
}
},
- hir::ExprKind::MethodCall(method, [obj], _) => if_chain! {
+ hir::ExprKind::MethodCall(method, obj, [], _) => if_chain! {
if ident_eq(name, obj) && method.ident.name == sym::clone;
if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
]);
/// Extracts a method call name, args, and `Span` of the method name.
-fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> {
- if let ExprKind::MethodCall(path, args, _) = recv.kind {
- if !args.iter().any(|e| e.span.from_expansion()) {
+fn method_call<'tcx>(
+ recv: &'tcx hir::Expr<'tcx>,
+) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> {
+ if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind {
+ if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
let name = path.ident.name.as_str();
- return Some((name, args, path.ident.span));
+ return Some((name, receiver, args, path.ident.span));
}
}
None
hir::ExprKind::Call(func, args) => {
from_iter_instead_of_collect::check(cx, expr, args, func);
},
- hir::ExprKind::MethodCall(method_call, args, _) => {
+ hir::ExprKind::MethodCall(method_call, receiver, args, _) => {
let method_span = method_call.ident.span;
- or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
- expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
- clone_on_copy::check(cx, expr, method_call.ident.name, args);
- clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
- inefficient_to_string::check(cx, expr, method_call.ident.name, args);
- single_char_add_str::check(cx, expr, args);
- into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args);
- single_char_pattern::check(cx, expr, method_call.ident.name, args);
- unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv);
+ or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+ expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+ clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
+ clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
+ inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args);
+ single_char_add_str::check(cx, expr, receiver, args);
+ into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
+ single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
+ unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
},
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
let mut info = BinaryExprInfo {
impl Methods {
#[allow(clippy::too_many_lines)]
fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
+ if let Some((name, recv, args, span)) = method_call(expr) {
match (name, args) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
zst_offset::check(cx, expr, recv);
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
("collect", []) => match method_call(recv) {
- Some((name @ ("cloned" | "copied"), [recv2], _)) => {
+ Some((name @ ("cloned" | "copied"), recv2, [], _)) => {
iter_cloned_collect::check(cx, name, expr, recv2);
},
- Some(("map", [m_recv, m_arg], _)) => {
+ Some(("map", m_recv, [m_arg], _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
},
- Some(("take", [take_self_arg, take_arg], _)) => {
+ Some(("take", take_self_arg, [take_arg], _)) => {
if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
}
_ => {},
},
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
- Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
- Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
+ Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
+ Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => {
iter_count::check(cx, expr, recv2, name2);
},
- Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
- Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg),
- Some(("bytes", [recv2], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
+ Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg),
+ Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg),
+ Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
_ => {},
},
("drain", [arg]) => {
iter_with_drain::check(cx, expr, recv, span, arg);
},
("ends_with", [arg]) => {
- if let ExprKind::MethodCall(_, _, span) = expr.kind {
+ if let ExprKind::MethodCall(.., span) = expr.kind {
case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
}
},
("expect", [_]) => match method_call(recv) {
- Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
- Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
+ Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv),
+ Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
},
("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
flat_map_option::check(cx, expr, arg, span);
},
("flatten", []) => match method_call(recv) {
- Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
- Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
+ Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
+ Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
_ => {},
},
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
("for_each", [_]) => {
- if let Some(("inspect", [_, _], span2)) = method_call(recv) {
+ if let Some(("inspect", _, [_], span2)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
}
},
iter_on_single_or_empty_collections::check(cx, expr, name, recv);
},
("join", [join_arg]) => {
- if let Some(("collect", _, span)) = method_call(recv) {
+ if let Some(("collect", _, _, span)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span);
}
},
("last", []) | ("skip", [_]) => {
- if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
} else {
map_err_ignore::check(cx, expr, m_arg);
}
- if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
+ if let Some((name, recv2, args, span2)) = method_call(recv) {
match (name, args) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
manual_ok_or::check(cx, expr, recv, def, map);
},
("next", []) => {
- if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _)) = method_call(recv) {
match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
}
},
("nth", [n_arg]) => match method_call(recv) {
- Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
- Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
- Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
- Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
+ Some(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+ Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
+ Some(("iter", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
+ Some(("iter_mut", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
},
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
},
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", [_arg]) => {
- if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
},
("unwrap", []) => {
match method_call(recv) {
- Some(("get", [recv, get_arg], _)) => {
+ Some(("get", recv, [get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, false);
},
- Some(("get_mut", [recv, get_arg], _)) => {
+ Some(("get_mut", recv, [get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true);
},
- Some(("or", [recv, or_arg], or_span)) => {
+ Some(("or", recv, [or_arg], or_span)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
},
_ => {},
},
("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
("unwrap_or", [u_arg]) => match method_call(recv) {
- Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
+ Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
},
- Some(("map", [m_recv, m_arg], span)) => {
+ Some(("map", m_recv, [m_arg], span)) => {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
},
- Some(("then_some", [t_recv, t_arg], _)) => {
+ Some(("then_some", t_recv, [t_arg], _)) => {
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
},
_ => {},
},
("unwrap_or_else", [u_arg]) => match method_call(recv) {
- Some(("map", [recv, map_arg], _))
+ Some(("map", recv, [map_arg], _))
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
_ => {
unwrap_or_else_default::check(cx, expr, recv, u_arg);
},
},
("zip", [arg]) => {
- if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind
+ if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
&& name.ident.name == sym::iter
{
range_zip_with_len::check(cx, expr, iter_recv, arg);
}
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
- if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call(recv) {
+ if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) {
search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
}
}
}
fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
- if let ExprKind::MethodCall(path, arguments, _) = argument.kind {
- let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
+ if let ExprKind::MethodCall(path, receiver, arguments, _) = argument.kind {
+ let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
// Only proceed if this is a call on some object of type std::fs::OpenOptions
- if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
- let argument_option = match arguments[1].kind {
+ if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 1 {
+ let argument_option = match arguments[0].kind {
ExprKind::Lit(ref span) => {
if let Spanned {
node: LitKind::Bool(lit),
_ => (),
}
- get_open_options(cx, &arguments[0], options);
+ get_open_options(cx, receiver, options);
}
}
}
let closure_expr = peel_blocks(&closure_body.value);
match &closure_expr.kind {
- hir::ExprKind::MethodCall(_, args, _) => {
+ hir::ExprKind::MethodCall(_, receiver, [], _) => {
if_chain! {
- if args.len() == 1;
- if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id);
+ if path_to_local_id(receiver, closure_body.params[0].pat.hir_id);
let adj = cx
.typeck_results()
- .expr_adjustments(&args[0])
+ .expr_adjustments(receiver)
.iter()
.map(|x| &x.kind)
.collect::<Box<[_]>>();
expr: &hir::Expr<'_>,
method_span: Span,
name: &str,
+ receiver: &'tcx hir::Expr<'_>,
args: &'tcx [hir::Expr<'_>],
) {
/// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
}
}
- if let [self_arg, arg] = args {
+ if let [arg] = args {
let inner_arg = if let hir::ExprKind::Block(
hir::Block {
stmts: [],
let or_has_args = !or_args.is_empty();
if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
let fun_span = if or_has_args { None } else { Some(fun.span) };
- check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span);
+ check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span);
}
},
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
- check_general_case(cx, name, method_span, self_arg, arg, expr.span, None);
+ check_general_case(cx, name, method_span, receiver, arg, expr.span, None);
},
_ => (),
}
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
if is_integer_const(cx, start, 0);
// `.len()` call
- if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind;
+ if let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind;
if len_path.ident.name == sym::len;
// `.iter()` and `.len()` called on same `Path`
if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind;
use rustc_hir as hir;
use rustc_lint::LateContext;
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
- single_char_push_string::check(cx, expr, args);
+ single_char_push_string::check(cx, expr, receiver, args);
} else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
- single_char_insert_string::check(cx, expr, args);
+ single_char_insert_string::check(cx, expr, receiver, args);
}
}
}
use super::SINGLE_CHAR_ADD_STR;
/// lint for length-1 `str`s as argument for `insert_str`
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
let mut applicability = Applicability::MachineApplicable;
- if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) {
+ if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
let base_string_snippet =
- snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability);
- let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability);
+ snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
+ let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string);
span_lint_and_sugg(
cx,
use super::SINGLE_CHAR_PATTERN;
const PATTERN_METHODS: [(&str, usize); 24] = [
- ("contains", 1),
- ("starts_with", 1),
- ("ends_with", 1),
- ("find", 1),
- ("rfind", 1),
- ("split", 1),
- ("split_inclusive", 1),
- ("rsplit", 1),
- ("split_terminator", 1),
- ("rsplit_terminator", 1),
- ("splitn", 2),
- ("rsplitn", 2),
- ("split_once", 1),
- ("rsplit_once", 1),
- ("matches", 1),
- ("rmatches", 1),
- ("match_indices", 1),
- ("rmatch_indices", 1),
- ("strip_prefix", 1),
- ("strip_suffix", 1),
- ("trim_start_matches", 1),
- ("trim_end_matches", 1),
- ("replace", 1),
- ("replacen", 1),
+ ("contains", 0),
+ ("starts_with", 0),
+ ("ends_with", 0),
+ ("find", 0),
+ ("rfind", 0),
+ ("split", 0),
+ ("split_inclusive", 0),
+ ("rsplit", 0),
+ ("split_terminator", 0),
+ ("rsplit_terminator", 0),
+ ("splitn", 1),
+ ("rsplitn", 1),
+ ("split_once", 0),
+ ("rsplit_once", 0),
+ ("matches", 0),
+ ("rmatches", 0),
+ ("match_indices", 0),
+ ("rmatch_indices", 0),
+ ("strip_prefix", 0),
+ ("strip_suffix", 0),
+ ("trim_start_matches", 0),
+ ("trim_end_matches", 0),
+ ("replace", 0),
+ ("replacen", 0),
];
/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
-pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ _expr: &hir::Expr<'_>,
+ method_name: Symbol,
+ receiver: &hir::Expr<'_>,
+ args: &[hir::Expr<'_>],
+) {
for &(method, pos) in &PATTERN_METHODS {
if_chain! {
- if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind();
+ if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind();
if *ty.kind() == ty::Str;
if method_name.as_str() == method && args.len() > pos;
let arg = &args[pos];
use super::SINGLE_CHAR_ADD_STR;
/// lint for length-1 `str`s as argument for `push_str`
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
let mut applicability = Applicability::MachineApplicable;
- if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
+ if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) {
let base_string_snippet =
- snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability);
+ snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
let sugg = format!("{}.push({})", base_string_snippet, extension_string);
span_lint_and_sugg(
cx,
let ctxt = expr.span.ctxt();
let mut parents = cx.tcx.hir().parent_iter(expr.hir_id);
if let (_, Node::Local(local)) = parents.next()?
- && let PatKind::Binding(BindingAnnotation::Mutable, iter_binding_id, iter_ident, None) = local.pat.kind
+ && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind
&& let (iter_stmt_id, Node::Stmt(_)) = parents.next()?
&& let (_, Node::Block(enclosing_block)) = parents.next()?
ctxt: SyntaxContext,
) -> Option<IndirectUsage<'tcx>> {
if let StmtKind::Local(Local {
- pat:
- Pat {
- kind: PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None),
- ..
- },
+ pat: Pat {
+ kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None),
+ ..
+ },
init: Some(init_expr),
hir_id: local_hir_id,
..
) -> Option<IterUsage> {
let (kind, span) = match iter.next() {
Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
- let (name, args) = if let ExprKind::MethodCall(name, [_, args @ ..], _) = e.kind {
+ let (name, args) = if let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind {
(name, args)
} else {
return None;
} else {
if_chain! {
if let Some((_, Node::Expr(next_expr))) = iter.next();
- if let ExprKind::MethodCall(next_name, [_], _) = next_expr.kind;
+ if let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind;
if next_name.ident.name == sym::next;
if next_expr.span.ctxt() == ctxt;
if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id);
}
},
_ if e.span.ctxt() != ctxt => (None, span),
- ExprKind::MethodCall(name, [_], _)
+ ExprKind::MethodCall(name, _, [], _)
if name.ident.name == sym::unwrap
&& cx
.typeck_results()
return;
}
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
- let target = &arglists[0][0];
+ let target = &arglists[0].0;
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
let ref_str = if *self_ty.kind() == ty::Str {
""
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
then {
let snippet = if_chain! {
- if let ExprKind::MethodCall(maybe_iter_method_name, [collection], _) = receiver.kind;
+ if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind;
if maybe_iter_method_name.ident.name == sym::iter;
if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
// This is a duplicate of what's happening in clippy_lints::methods::method_call,
// which isn't ideal, We want to get the method call span,
// but prefer to avoid changing the signature of the function itself.
- if let hir::ExprKind::MethodCall(_, _, span) = expr.kind {
+ if let hir::ExprKind::MethodCall(.., span) = expr.kind {
span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
diag.span_suggestion(
span,
// The two exprs are method calls.
// Check to see that the function is the same and the arguments are mirrored
// This is enough because the receiver of the method is listed in the arguments
- (ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => {
+ (
+ ExprKind::MethodCall(left_segment, left_receiver, left_args, _),
+ ExprKind::MethodCall(right_segment, right_receiver, right_args, _),
+ ) => {
left_segment.ident == right_segment.ident
&& iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
+ && mirrored_exprs(left_receiver, a_ident, right_receiver, b_ident)
},
// Two tuples with mirrored contents
(ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
] = &closure_body.params;
- if let ExprKind::MethodCall(method_path, [left_expr, right_expr], _) = closure_body.value.kind;
+ if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind;
if method_path.ident.name == sym::cmp;
if is_trait_method(cx, &closure_body.value, sym::Ord);
then {
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'tcx>,
method_name: Symbol,
- args: &'tcx [Expr<'tcx>],
+ receiver: &'tcx Expr<'_>,
+ args: &'tcx [Expr<'_>],
msrv: Option<RustcVersion>,
) {
if_chain! {
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if let [receiver] = args;
+ if args.is_empty();
then {
if is_cloned_or_copied(cx, method_name, method_def_id) {
unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
) -> bool {
if_chain! {
if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
- if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call);
+ if let Some((callee_def_id, call_substs, call_receiver, call_args)) = get_callee_substs_and_args(cx, maybe_call);
let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
- if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id);
+ let index = if let Some(call_receiver) = call_receiver {
+ std::iter::once(call_receiver).chain(call_args.iter()).position(|arg| arg.hir_id == maybe_arg.hir_id)
+ } else {
+ call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id)
+ };
+ if let Some(i) = index;
if let Some(input) = fn_sig.inputs().get(i);
let (input, n_refs) = peel_mid_ty_refs(*input);
if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input);
fn get_callee_substs_and_args<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'tcx>,
-) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> {
+) -> Option<(DefId, SubstsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> {
if_chain! {
if let ExprKind::Call(callee, args) = expr.kind;
let callee_ty = cx.typeck_results().expr_ty(callee);
if let ty::FnDef(callee_def_id, _) = callee_ty.kind();
then {
let substs = cx.typeck_results().node_substs(callee.hir_id);
- return Some((*callee_def_id, substs, args));
+ return Some((*callee_def_id, substs, None, args));
}
}
if_chain! {
- if let ExprKind::MethodCall(_, args, _) = expr.kind;
+ if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind;
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
then {
let substs = cx.typeck_results().node_substs(expr.hir_id);
- return Some((method_def_id, substs, args));
+ return Some((method_def_id, substs, Some(receiver), args));
}
}
None
}
}
- if let hir::ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind {
+ if let hir::ExprKind::MethodCall(path, self_arg, ..) = &expr.kind {
if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) {
Some(self_arg)
} else {
self.addr_of_exprs.push(parent);
return;
},
- ExprKind::MethodCall(_, args, _) => {
+ ExprKind::MethodCall(.., args, _) => {
if_chain! {
- if args.iter().skip(1).all(|arg| !self.is_binding(arg));
+ if args.iter().all(|arg| !self.is_binding(arg));
if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id);
let method_ty = self.cx.tcx.type_of(method_def_id);
let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder();
.qpath_res(qpath, path.hir_id)
.opt_def_id()
.and_then(|def_id| match cx.tcx.get_diagnostic_name(def_id) {
- Some(sym::cmp_min) => fetch_const(cx, args, MinMax::Min),
- Some(sym::cmp_max) => fetch_const(cx, args, MinMax::Max),
+ Some(sym::cmp_min) => fetch_const(cx, None, args, MinMax::Min),
+ Some(sym::cmp_max) => fetch_const(cx, None, args, MinMax::Max),
_ => None,
})
} else {
None
}
},
- ExprKind::MethodCall(path, args, _) => {
+ ExprKind::MethodCall(path, receiver, args @ [_], _) => {
if_chain! {
- if let [obj, _] = args;
- if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
+ if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
then {
if path.ident.name == sym!(max) {
- fetch_const(cx, args, MinMax::Max)
+ fetch_const(cx, Some(receiver), args, MinMax::Max)
} else if path.ident.name == sym!(min) {
- fetch_const(cx, args, MinMax::Min)
+ fetch_const(cx, Some(receiver), args, MinMax::Min)
} else {
None
}
}
}
-fn fetch_const<'a>(cx: &LateContext<'_>, args: &'a [Expr<'a>], m: MinMax) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
- if args.len() != 2 {
+fn fetch_const<'a>(
+ cx: &LateContext<'_>,
+ receiver: Option<&'a Expr<'a>>,
+ args: &'a [Expr<'a>],
+ m: MinMax,
+) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
+ let mut args = receiver.into_iter().chain(args.into_iter());
+ let arg0 = args.next()?;
+ let arg1 = args.next()?;
+ if args.next().is_some() {
return None;
}
- constant_simple(cx, cx.typeck_results(), &args[0]).map_or_else(
- || constant_simple(cx, cx.typeck_results(), &args[1]).map(|c| (m, c, &args[0])),
+ constant_simple(cx, cx.typeck_results(), arg0).map_or_else(
+ || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)),
|c| {
- if constant_simple(cx, cx.typeck_results(), &args[1]).is_none() {
+ if constant_simple(cx, cx.typeck_results(), arg1).is_none() {
// otherwise ignore
- Some((m, c, &args[1]))
+ Some((m, c, arg1))
} else {
None
}
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
- self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt,
- StmtKind, TyKind,
+ self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind,
+ Stmt, StmtKind, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
return;
}
for arg in iter_input_pats(decl, body) {
- if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind {
+ if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind {
span_lint(
cx,
TOPLEVEL_REF_ARG,
if_chain! {
if !in_external_macro(cx.tcx.sess, stmt.span);
if let StmtKind::Local(local) = stmt.kind;
- if let PatKind::Binding(an, .., name, None) = local.pat.kind;
+ if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind;
if let Some(init) = local.init;
- if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut;
then {
// use the macro callsite when the init span (but not the whole local span)
// comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];`
} else {
Sugg::hir(cx, init, "..")
};
- let (mutopt, initref) = if an == BindingAnnotation::RefMut {
+ let (mutopt, initref) = if mutabl == Mutability::Mut {
("mut ", sugg_init.mut_addr())
} else {
("", sugg_init.addr())
use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_ast::ast::{BindingMode, Mutability, Pat, PatKind};
+use rustc_ast::ast::{Pat, PatKind};
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
use super::REDUNDANT_PATTERN;
pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
- if let PatKind::Ident(left, ident, Some(ref right)) = pat.kind {
- let left_binding = match left {
- BindingMode::ByRef(Mutability::Mut) => "ref mut ",
- BindingMode::ByRef(Mutability::Not) => "ref ",
- BindingMode::ByValue(..) => "",
- };
-
+ if let PatKind::Ident(ann, ident, Some(ref right)) = pat.kind {
if let PatKind::Wild = right.kind {
span_lint_and_sugg(
cx,
ident.name, ident.name,
),
"try",
- format!("{}{}", left_binding, ident.name),
+ format!("{}{}", ann.prefix_str(), ident.name),
Applicability::MachineApplicable,
);
}
if let ExprKind::Path(ref path) = fn_expr.kind {
check_arguments(
cx,
- arguments,
+ arguments.iter().collect(),
cx.typeck_results().expr_ty(fn_expr),
&rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
"function",
);
}
},
- ExprKind::MethodCall(path, arguments, _) => {
+ ExprKind::MethodCall(path, receiver, arguments, _) => {
let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
let substs = cx.typeck_results().node_substs(e.hir_id);
let method_type = cx.tcx.bound_type_of(def_id).subst(cx.tcx, substs);
- check_arguments(cx, arguments, method_type, path.ident.as_str(), "method");
+ check_arguments(
+ cx,
+ std::iter::once(receiver).chain(arguments.iter()).collect(),
+ method_type,
+ path.ident.as_str(),
+ "method",
+ );
},
_ => (),
}
fn check_arguments<'tcx>(
cx: &LateContext<'tcx>,
- arguments: &[Expr<'_>],
+ arguments: Vec<&Expr<'_>>,
type_definition: Ty<'tcx>,
name: &str,
fn_kind: &str,
use clippy_utils::diagnostics::span_lint_and_sugg;
use if_chain::if_chain;
-use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
+use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
match &p.ty.kind {
TyKind::Path(None, path) => {
- if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
+ if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), _, _) = p.pat.kind {
check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
}
},
TyKind::Rptr(lifetime, mut_ty) => {
if_chain! {
if let TyKind::Path(None, path) = &mut_ty.ty.kind;
- if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
+ if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind;
then {
check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
}
if let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind;
// Check sub_pat got a `ref` keyword (excluding `ref mut`).
- if let PatKind::Binding(BindingAnnotation::Ref, .., spanned_name, _) = sub_pat.kind;
+ if let PatKind::Binding(BindingAnnotation::REF, .., spanned_name, _) = sub_pat.kind;
let parent_id = cx.tcx.hir().get_parent_node(pat.hir_id);
if let Some(parent_node) = cx.tcx.hir().find(parent_id);
then {
if_chain! {
// Check the method name is `for_each`.
- if let ExprKind::MethodCall(method_name, [for_each_recv, for_each_arg], _) = expr.kind;
+ if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind;
if method_name.ident.name == Symbol::intern("for_each");
// Check `for_each` is an associated function of `Iterator`.
if is_trait_method(cx, expr, sym::Iterator);
// Checks the receiver of `for_each` is also a method call.
- if let ExprKind::MethodCall(_, [iter_recv], _) = for_each_recv.kind;
+ if let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind;
// Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or
// `v.foo().iter().for_each()` must be skipped.
if matches!(
if let Local {
init: None,
pat: &Pat {
- kind: PatKind::Binding(BindingAnnotation::Unannotated, binding_id, _, None),
+ kind: PatKind::Binding(BindingAnnotation::NONE, binding_id, _, None),
..
},
source: LocalSource::Normal,
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Node, PatKind, QPath, TyKind};
+use rustc_hir::{
+ BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind,
+};
use rustc_hir::{HirIdMap, HirIdSet};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
if !implements_borrow_trait;
if !all_borrowable_trait;
- if let PatKind::Binding(mode, canonical_id, ..) = arg.pat.kind;
+ if let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind;
if !moved_vars.contains(&canonical_id);
then {
- if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut {
- continue;
- }
-
// Dereference suggestion
let sugg = |diag: &mut Diagnostic| {
if let ty::Adt(def, ..) = ty.kind() {
impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
match &expr.kind {
- ExprKind::MethodCall(path, [func, param], _) => {
+ ExprKind::MethodCall(path, func, [param], _) => {
let obj_ty = cx.typeck_results().expr_ty(func).peel_refs();
if_chain! {
}
return;
},
- ExprKind::MethodCall(_, args, _)
+ ExprKind::MethodCall(_, receiver, args, _)
if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| {
id == param.fn_id
&& has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id))
}) =>
{
- if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
+ if let Some(idx) = std::iter::once(receiver).chain(args.iter()).position(|arg| arg.hir_id == child_id) {
param.uses.push(Usage::new(span, idx));
}
return;
fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
let typeck = cx.typeck_results();
let (arg, arg_span) = match expr.kind {
- ExprKind::MethodCall(.., [arg], _)
+ ExprKind::MethodCall(_, arg, [], _)
if typeck
.type_dependent_def_id(expr.hir_id)
.and_then(|id| cx.tcx.trait_of_item(id))
right: &'tcx Expr<'_>,
) {
if op == BinOpKind::Div
- && let ExprKind::MethodCall(method_path, [self_arg], _) = left.kind
+ && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
&& let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right)
{
}
if_chain! {
- if let ExprKind::MethodCall(method_name, [ref self_arg, ..], _) = expr.kind;
+ if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
if sym!(signum) == method_name.ident.name;
// Check that the receiver of the signum() is a float (expressions[0] is the receiver of
// the method call)
if let ItemKind::Impl(item) = &item.kind;
if let Some(of_trait) = &item.of_trait;
if let Some(seg) = of_trait.path.segments.last();
- if let Some(Res::Def(_, trait_id)) = seg.res;
+ if let Res::Def(_, trait_id) = seg.res;
if trait_id == bin_op;
if let Some(generic_args) = seg.args;
if let Some(GenericArg::Type(other_ty)) = generic_args.args.last();
.filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2)))
.all(|(x, y)| x.is_imm_ref() && y.is_imm_ref());
then {
- let capture_mut = if bind_annotation == BindingAnnotation::Mutable { "mut " } else { "" };
+ let capture_mut = if bind_annotation == BindingAnnotation::MUT { "mut " } else { "" };
let some_body = peel_blocks(if_then);
let none_body = peel_blocks(if_else);
let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" };
let (as_ref, as_mut) = match &expr.kind {
ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
- _ => (bind_annotation == BindingAnnotation::Ref, bind_annotation == BindingAnnotation::RefMut),
+ _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT),
};
// Check if captures the closure will need conflict with borrows made in the scrutinee.
// if function has a body and parameter is annotated with mut, ignore
if let Some(param) = fn_body.and_then(|body| body.params.get(index)) {
match param.pat.kind {
- PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {},
+ PatKind::Binding(BindingAnnotation::NONE, _, _, _) => {},
_ => continue,
}
}
Some((Node::Stmt(_), _)) => (),
Some((Node::Local(l), _)) => {
// Only trace simple bindings. e.g `let x = y;`
- if let PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) = l.pat.kind {
+ if let PatKind::Binding(BindingAnnotation::NONE, id, _, None) = l.pat.kind {
self.bindings.insert(id, args_idx);
} else {
set_skip_flag();
set_skip_flag();
}
},
- ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => {
- let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
+ ExprKind::MethodCall(name, self_arg, expr_args, _) => {
+ let i = std::iter::once(self_arg)
+ .chain(expr_args.iter())
+ .position(|arg| arg.hir_id == child_id)
+ .unwrap_or(0);
if i == 0 {
// Check if the method can be renamed.
let name = name.ident.as_str();
.filter_map(|(i, arg)| {
let param = &body.params[arg.idx];
match param.pat.kind {
- PatKind::Binding(BindingAnnotation::Unannotated, id, _, None)
+ PatKind::Binding(BindingAnnotation::NONE, id, _, None)
if !is_lint_allowed(cx, PTR_ARG, param.hir_id) =>
{
Some((id, i))
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> {
- if let ExprKind::MethodCall(path_segment, [arg_0, arg_1, ..], _) = &expr.kind {
+ if let ExprKind::MethodCall(path_segment, arg_0, [arg_1, ..], _) = &expr.kind {
if is_expr_ty_raw_ptr(cx, arg_0) {
if path_segment.ident.name == sym::offset {
return Some((arg_0, arg_1, Method::Offset));
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, PathSegment, QPath};
+use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, Node, PatKind, PathSegment, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
if_chain! {
if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
if !is_else_clause(cx.tcx, expr);
- if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind;
+ if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind;
let caller_ty = cx.typeck_results().expr_ty(caller);
let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else);
if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block);
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr);
if !is_else_clause(cx.tcx, expr);
if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind;
- if let PatKind::Binding(annot, bind_id, ident, None) = field.kind;
+ if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind;
let caller_ty = cx.typeck_results().expr_ty(let_expr);
let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else);
if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id))
then {
let mut applicability = Applicability::MachineApplicable;
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
- let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_)));
let sugg = format!(
"{}{}?{}",
receiver_str,
- if by_ref { ".as_ref()" } else { "" },
+ if by_ref == ByRef::Yes { ".as_ref()" } else { "" },
if requires_semi { ";" } else { "" }
);
span_lint_and_sugg(
// finds use of `_.read(&mut v)`
let mut read_found = false;
let mut visitor = expr_visitor_no_bodies(|expr| {
- if let ExprKind::MethodCall(path, [_self, arg], _) = expr.kind
+ if let ExprKind::MethodCall(path, _self, [arg], _) = expr.kind
&& let PathSegment { ident: read_or_read_exact, .. } = *path
&& matches!(read_or_read_exact.as_str(), "read" | "read_exact")
&& let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind
if mut_ty.mutbl == Mutability::Not;
if let TyKind::Path(ref qpath) = &mut_ty.ty.kind;
let last = last_path_segment(qpath);
- if let Some(res) = last.res;
- if let Some(def_id) = res.opt_def_id();
+ if let Some(def_id) = last.res.opt_def_id();
if cx.tcx.is_diagnostic_item(sym::Option, def_id);
if let Some(params) = last_path_segment(qpath).args ;
};
if_chain! {
// Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods
- if let ExprKind::MethodCall(method_path, [ptr_self, .., count], _) = expr.kind;
+ if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind;
let method_ident = method_path.ident.as_str();
if METHODS.iter().any(|m| *m == method_ident);
// Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
if_chain! {
if let StmtKind::Local(local) = stmt.kind;
- if let PatKind::Binding(BindingAnnotation::Mutable, local_id, _, None) = local.pat.kind;
+ if let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind;
if let Some(init) = local.init;
if let Some(len_arg) = Self::is_vec_with_capacity(cx, init);
fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
if_chain! {
if self.initialization_found;
- if let ExprKind::MethodCall(path, [self_arg, extend_arg], _) = expr.kind;
+ if let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind;
if path_to_local_id(self_arg, self.vec_alloc.local_id);
if path.ident.name == sym!(extend);
if self.is_repeat_take(extend_arg);
/// Checks if the given expression is resizing a vector with 0
fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
if self.initialization_found
- && let ExprKind::MethodCall(path, [self_arg, len_arg, fill_arg], _) = expr.kind
+ && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
&& path_to_local_id(self_arg, self.vec_alloc.local_id)
&& path.ident.name == sym!(resize)
// Check that is filled with 0
// Check that len expression is equals to `with_capacity` expression
if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
self.slow_expression = Some(InitializationType::Resize(expr));
- } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" {
+ } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
self.slow_expression = Some(InitializationType::Resize(expr));
}
}
/// Returns `true` if give expression is `repeat(0).take(...)`
fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
if_chain! {
- if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind;
+ if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind;
if take_path.ident.name == sym!(take);
// Check that take is applied to `repeat(0)`
if self.is_repeat_zero(recv);
// Check that len expression is equals to `with_capacity` expression
if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
return true;
- } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" {
+ } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
return true;
}
}
let (method_names, expressions, _) = method_calls(left, 1);
if method_names.len() == 1;
if expressions.len() == 1;
- if expressions[0].len() == 1;
+ if expressions[0].1.is_empty();
if method_names[0] == sym!(as_bytes);
// Check for slicer
then {
let mut applicability = Applicability::MachineApplicable;
- let string_expression = &expressions[0][0];
+ let string_expression = &expressions[0].0;
let snippet_app = snippet_with_applicability(
cx,
}
if_chain! {
- if let ExprKind::MethodCall(path, args, _) = &e.kind;
+ if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
if path.ident.name == sym!(as_bytes);
- if let ExprKind::Lit(lit) = &args[0].kind;
+ if let ExprKind::Lit(lit) = &receiver.kind;
if let LitKind::Str(lit_content, _) = &lit.node;
then {
- let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
+ let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#);
let mut applicability = Applicability::MachineApplicable;
if callsite.starts_with("include_str!") {
span_lint_and_sugg(
e.span,
"calling `as_bytes()` on `include_str!(..)`",
"consider using `include_bytes!(..)` instead",
- snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
+ snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen(
"include_str",
"include_bytes",
1,
);
} else if lit_content.as_str().is_ascii()
&& lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
- && !args[0].span.from_expansion()
+ && !receiver.span.from_expansion()
{
span_lint_and_sugg(
cx,
"consider using a byte string literal instead",
format!(
"b{}",
- snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
+ snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
),
applicability,
);
}
if_chain! {
- if let ExprKind::MethodCall(path, [recv], _) = &e.kind;
+ if let ExprKind::MethodCall(path, recv, [], _) = &e.kind;
if path.ident.name == sym!(into_bytes);
- if let ExprKind::MethodCall(path, [recv], _) = &recv.kind;
+ if let ExprKind::MethodCall(path, recv, [], _) = &recv.kind;
if matches!(path.ident.name.as_str(), "to_owned" | "to_string");
if let ExprKind::Lit(lit) = &recv.kind;
if let LitKind::Str(lit_content, _) = &lit.node;
impl<'tcx> LateLintPass<'tcx> for StrToString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
if_chain! {
- if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+ if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
if path.ident.name == sym::to_string;
let ty = cx.typeck_results().expr_ty(self_arg);
if let ty::Ref(_, ty, ..) = ty.kind();
impl<'tcx> LateLintPass<'tcx> for StringToString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
if_chain! {
- if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+ if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
if path.ident.name == sym::to_string;
let ty = cx.typeck_results().expr_ty(self_arg);
if is_type_diagnostic_item(cx, ty, sym::String);
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
let tyckres = cx.typeck_results();
if_chain! {
- if let ExprKind::MethodCall(path, [split_recv], split_ws_span) = expr.kind;
+ if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind;
if path.ident.name == sym!(split_whitespace);
if let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id);
if cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id);
- if let ExprKind::MethodCall(path, [_trim_recv], trim_span) = split_recv.kind;
+ if let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind;
if let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str();
if let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id);
if is_one_of_trim_diagnostic_items(cx, trim_def_id);
if let ExprKind::Path(path) = &func.kind;
if let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id();
if match_libc_symbol(cx, did, "strlen");
- if let ExprKind::MethodCall(path, [self_arg], _) = recv.kind;
+ if let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind;
if !recv.span.from_expansion();
if path.ident.name == sym::as_ptr;
then {
impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if_chain! {
- if let hir::ExprKind::MethodCall(is_some_path, is_some_args, _) = &expr.kind;
+ if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind;
if is_some_path.ident.name.as_str() == "is_some";
- if let [to_digit_expr] = &**is_some_args;
then {
let match_result = match &to_digit_expr.kind {
- hir::ExprKind::MethodCall(to_digits_path, to_digit_args, _) => {
+ hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => {
if_chain! {
- if let [char_arg, radix_arg] = &**to_digit_args;
if to_digits_path.ident.name.as_str() == "to_digit";
let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg);
if *char_arg_ty.kind() == ty::Char;
then {
- Some((true, char_arg, radix_arg))
+ Some((true, *char_arg, radix_arg))
} else {
None
}
}
hir::ExprKind::Call(to_digits_call, to_digit_args) => {
if_chain! {
- if let [char_arg, radix_arg] = &**to_digit_args;
+ if let [char_arg, radix_arg] = *to_digit_args;
if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind;
if let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id);
if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id();
if !bound_predicate.span.from_expansion();
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
if let Some(PathSegment {
- res: Some(Res::SelfTy{ trait_: Some(def_id), alias_to: _ }), ..
+ res: Res::SelfTy{ trait_: Some(def_id), alias_to: _ }, ..
}) = segments.first();
if let Some(
Node::Item(
});
}
},
- ExprKind::MethodCall(path, [self_expr, _], _) if is_reserve(cx, path, self_expr) => {
+ ExprKind::MethodCall(path, self_expr, [_], _) if is_reserve(cx, path, self_expr) => {
return Some(TargetVec {
location: VecLocation::Expr(self_expr),
init_kind: None,
}
});
match expr.kind {
- ExprKind::MethodCall(path, [self_expr, _], _) => {
+ 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))
impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if let ExprKind::MethodCall(_, args, _) = expr.kind {
+ if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind {
let arg_indices = get_args_to_check(cx, expr);
+ let args = std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>();
for (i, trait_name) in arg_indices {
if i < args.len() {
match check_arg(cx, &args[i]) {
locals_to_check: &mut Vec<HirId>,
seen_locals: &mut HirIdSet,
) -> bool {
- let (id, args) = match e.kind {
+ let (id, receiver, args) = match e.kind {
ExprKind::Call(
Expr {
kind: ExprKind::Path(ref path),
},
args,
) => match cx.qpath_res(path, *hir_id) {
- Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, args),
+ Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, None, args),
_ => return false,
},
- ExprKind::MethodCall(_, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
- Some(id) => (id, args),
+ ExprKind::MethodCall(_, receiver, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
+ Some(id) => (id, Some(receiver), args),
None => return false,
},
ExprKind::Path(QPath::Resolved(None, path)) => {
};
let sig = cx.tcx.fn_sig(id).skip_binder();
if let ty::Param(output_ty) = *sig.output().kind() {
+ let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver {
+ std::iter::once(receiver).chain(args.iter()).collect()
+ } else {
+ args.iter().collect()
+ };
sig.inputs().iter().zip(args).all(|(&ty, arg)| {
!ty.is_param(output_ty.index) || each_value_source_needs_inference(cx, arg, locals_to_check, seen_locals)
})
}
}
- match expr.kind {
- ExprKind::Call(_, args) | ExprKind::MethodCall(_, args, _) => {
- let args_to_recover = args
- .iter()
- .filter(|arg| {
- if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
- !matches!(
- &arg.kind,
- ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
- )
- } else {
- false
- }
- })
- .collect::<Vec<_>>();
- if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
- lint_unit_args(cx, expr, &args_to_recover);
+ let args: Vec<_> = match expr.kind {
+ ExprKind::Call(_, args) => args.iter().collect(),
+ ExprKind::MethodCall(_, receiver, args, _) => std::iter::once(receiver).chain(args.iter()).collect(),
+ _ => return,
+ };
+
+ let args_to_recover = args
+ .into_iter()
+ .filter(|arg| {
+ if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
+ !matches!(
+ &arg.kind,
+ ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
+ )
+ } else {
+ false
}
- },
- _ => (),
+ })
+ .collect::<Vec<_>>();
+ if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
+ lint_unit_args(cx, expr, &args_to_recover.as_slice());
}
}
struct Visitor;
impl MutVisitor for Visitor {
fn visit_pat(&mut self, pat: &mut P<Pat>) {
- use ast::{BindingMode::*, Mutability::*};
+ use ast::BindingAnnotation;
noop_visit_pat(pat, self);
let target = match &mut pat.kind {
// `i @ a | b`, `box a | b`, and `& mut? a | b`.
Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
- Ref(p, Not) if matches!(p.kind, Ident(ByValue(Mut), ..)) => p, // `&(mut x)`
+ Ref(p, Mutability::Not) if matches!(p.kind, Ident(BindingAnnotation::MUT, ..)) => p, // `&(mut x)`
_ => return,
};
target.kind = Paren(P(take_pat(target)));
check_map_error(cx, res, expr);
}
},
- hir::ExprKind::MethodCall(path, [ref arg_0, ..], _) => match path.ident.as_str() {
+ hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() {
"expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => {
check_map_error(cx, arg_0, expr);
},
fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
let mut call = call;
- while let hir::ExprKind::MethodCall(path, args, _) = call.kind {
+ while let hir::ExprKind::MethodCall(path, receiver, ..) = call.kind {
if matches!(path.ident.as_str(), "or" | "or_else" | "ok") {
- call = &args[0];
+ call = receiver;
} else {
break;
}
}
fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>, is_await: bool) {
- if let hir::ExprKind::MethodCall(path, _, _) = call.kind {
+ if let hir::ExprKind::MethodCall(path, ..) = call.kind {
let symbol = path.ident.as_str();
let read_trait = if is_await {
match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT)
ident: method_name_ident,
..
},
- [self_arg, remaining_args @ ..],
+ self_arg,
+ remaining_args,
_,
) => {
let method_name = method_name_ident.name.as_str();
return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false);
} else {
if_chain! {
- if let ExprKind::MethodCall(method_name, args, _) = &expr.kind;
- if let Some(local_id) = path_to_local(&args[0]);
- let ty = cx.typeck_results().expr_ty(&args[0]);
+ if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind;
+ if let Some(local_id) = path_to_local(receiver);
+ let ty = cx.typeck_results().expr_ty(receiver);
let name = method_name.ident.as_str();
if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name);
then {
- assert!(args.len() == 1);
+ assert!(args.len() == 0);
let unwrappable = match name {
"is_some" | "is_ok" => true,
"is_err" | "is_none" => false,
} else {
// find `unwrap[_err]()` calls:
if_chain! {
- if let ExprKind::MethodCall(method_name, [self_arg, ..], _) = expr.kind;
+ if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
if let Some(id) = path_to_local(self_arg);
if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name);
let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name);
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
// check for `expect`
if let Some(arglists) = method_chain_args(expr, &["expect"]) {
- let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+ let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
{
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
- let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+ let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
{
}
},
- ExprKind::MethodCall(name, .., [recv, ..], _) => {
+ ExprKind::MethodCall(name, recv, ..) => {
if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" {
let a = cx.typeck_results().expr_ty(e);
let b = cx.typeck_results().expr_ty(recv);
use rustc_ast::LitIntType;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
-use rustc_hir::{ArrayLen, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
+use rustc_hir::{
+ ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
+};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::{Ident, Symbol};
self.expr(func);
self.slice(args, |e| self.expr(e));
},
- ExprKind::MethodCall(method_name, args, _) => {
- bind!(self, method_name, args);
- kind!("MethodCall({method_name}, {args}, _)");
+ ExprKind::MethodCall(method_name, receiver, args, _) => {
+ bind!(self, method_name, receiver, args);
+ kind!("MethodCall({method_name}, {receiver}, {args}, _)");
self.ident(field!(method_name.ident));
+ self.expr(receiver);
self.slice(args, |e| self.expr(e));
},
ExprKind::Tup(elements) => {
}
fn body(&self, body_id: &Binding<hir::BodyId>) {
- let expr = &self.cx.tcx.hir().body(body_id.value).value;
+ let expr = self.cx.tcx.hir().body(body_id.value).value;
bind!(self, expr);
out!("let {expr} = &cx.tcx.hir().body({body_id}).value;");
self.expr(expr);
match pat.value.kind {
PatKind::Wild => kind!("Wild"),
- PatKind::Binding(anno, .., name, sub) => {
+ PatKind::Binding(ann, _, name, sub) => {
bind!(self, name);
opt_bind!(self, sub);
- kind!("Binding(BindingAnnotation::{anno:?}, _, {name}, {sub})");
+ let ann = match ann {
+ BindingAnnotation::NONE => "NONE",
+ BindingAnnotation::REF => "REF",
+ BindingAnnotation::MUT => "MUT",
+ BindingAnnotation::REF_MUT => "REF_MUT",
+ };
+ kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})");
self.ident(name);
sub.if_some(|p| self.pat(p));
},
if let ["expn_data", "outer_expn"] = method_names.as_slice();
let args = arg_lists[1];
if args.len() == 1;
- let self_arg = &args[0];
+ let self_arg = &args.0;
let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
then {
|| get_parent_expr(cx, last_place)
.map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _)));
},
- ExprKind::MethodCall(_, [recv, ..], _)
+ ExprKind::MethodCall(_, recv, ..)
if recv.hir_id == e.hir_id
&& adjusted_mut == Mutability::Mut
&& !adjusted_ty.peel_refs().is_slice() =>
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
if let Some(init_expr) = local.init
- && let PatKind::Binding(BindingAnnotation::Mutable, id, name, None) = local.pat.kind
+ && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind
&& !in_external_macro(cx.sess(), local.span)
&& let Some(init) = get_vec_init_kind(cx, init_expr)
&& !matches!(init, VecInitKind::WithExprCapacity(_))
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
if let Some(searcher) = self.searcher.take() {
if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
- && let ExprKind::MethodCall(name, [self_arg, _], _) = expr.kind
+ && let ExprKind::MethodCall(name, self_arg, [_], _) = expr.kind
&& path_to_local_id(self_arg, searcher.local_id)
&& name.ident.as_str() == "push"
{
ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
ExprKind::Lit(ref lit) => lit_search_pat(&lit.node),
ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")),
- ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
+ ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
ExprKind::Call(first, [.., last])
- | ExprKind::MethodCall(_, [first, .., last], _)
+ | ExprKind::MethodCall(_, first, [.., last], _)
| ExprKind::Binary(_, first, last)
| ExprKind::Tup([first, .., last])
| ExprKind::Assign(first, last, _)
});
}
-pub fn span_lint_hir(
- cx: &LateContext<'_>,
- lint: &'static Lint,
- hir_id: HirId,
- sp: Span,
- msg: &str,
-) {
+pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
let mut diag = diag.build(msg);
docs_link(&mut diag, lint);
}
/// Determine the eagerness of the given function call.
-fn fn_eagerness<'tcx>(
- cx: &LateContext<'tcx>,
- fn_id: DefId,
- name: Symbol,
- args: &'tcx [Expr<'_>],
-) -> EagernessSuggestion {
+fn fn_eagerness<'tcx>(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
use EagernessSuggestion::{Eager, Lazy, NoChange};
let name = name.as_str();
None => return Lazy,
};
- if (name.starts_with("as_") || name == "len" || name == "is_empty") && args.len() == 1 {
+ if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg {
if matches!(
cx.tcx.crate_name(fn_id.krate),
sym::std | sym::core | sym::alloc | sym::proc_macro
},
Res::Def(_, id) => match path {
QPath::Resolved(_, p) => {
- self.eagerness |= fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, args);
+ self.eagerness |=
+ fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, !args.is_empty());
},
QPath::TypeRelative(_, name) => {
- self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, args);
+ self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, !args.is_empty());
},
QPath::LangItem(..) => self.eagerness = Lazy,
},
self.eagerness |= NoChange;
return;
},
- ExprKind::MethodCall(name, args, _) => {
+ ExprKind::MethodCall(name, ..) => {
self.eagerness |= self
.cx
.typeck_results()
.type_dependent_def_id(e.hir_id)
- .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, args));
+ .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true));
},
ExprKind::Index(_, e) => {
let ty = self.cx.typeck_results().expr_ty_adjusted(e);
use rustc_hir::def::Res;
use rustc_hir::HirIdMap;
use rustc_hir::{
- ArrayLen, BinOpKind, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard,
- HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath,
- Stmt, StmtKind, Ty, TyKind, TypeBinding,
+ ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
+ GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
+ PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::LateContext;
&& self.eq_expr(l.body, r.body)
})
},
- (&ExprKind::MethodCall(l_path, l_args, _), &ExprKind::MethodCall(r_path, r_args, _)) => {
- self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
+ (
+ &ExprKind::MethodCall(l_path, l_receiver, l_args, _),
+ &ExprKind::MethodCall(r_path, r_receiver, r_args, _),
+ ) => {
+ self.inner.allow_side_effects
+ && self.eq_path_segment(l_path, r_path)
+ && self.eq_expr(l_receiver, r_receiver)
+ && self.eq_exprs(l_args, r_args)
},
(&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => {
self.eq_expr(le, re) && self.eq_array_length(ll, rl)
s.hash(&mut self.s);
},
- ExprKind::MethodCall(path, args, ref _fn_span) => {
+ ExprKind::MethodCall(path, receiver, args, ref _fn_span) => {
self.hash_name(path.ident.name);
+ self.hash_expr(receiver);
self.hash_exprs(args);
},
ExprKind::ConstBlock(ref l_id) => {
pub fn hash_pat(&mut self, pat: &Pat<'_>) {
std::mem::discriminant(&pat.kind).hash(&mut self.s);
match pat.kind {
- PatKind::Binding(ann, _, _, pat) => {
- std::mem::discriminant(&ann).hash(&mut self.s);
+ PatKind::Binding(BindingAnnotation(by_ref, mutability), _, _, pat) => {
+ std::mem::discriminant(&by_ref).hash(&mut self.s);
+ std::mem::discriminant(&mutability).hash(&mut self.s);
if let Some(pat) = pat {
self.hash_pat(pat);
}
let hir = cx.tcx.hir();
if_chain! {
if let Some(Node::Pat(pat)) = hir.find(hir_id);
- if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..));
+ if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..));
let parent = hir.get_parent_node(hir_id);
if let Some(Node::Local(local)) = hir.find(parent);
then {
.map_or(&[][..], |a| a.args)
.iter()
.filter_map(|a| match a {
- hir::GenericArg::Type(ty) => Some(ty),
+ hir::GenericArg::Type(ty) => Some(*ty),
_ => None,
})
}
pub fn method_calls<'tcx>(
expr: &'tcx Expr<'tcx>,
max_depth: usize,
-) -> (Vec<Symbol>, Vec<&'tcx [Expr<'tcx>]>, Vec<Span>) {
+) -> (Vec<Symbol>, Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>, Vec<Span>) {
let mut method_names = Vec::with_capacity(max_depth);
let mut arg_lists = Vec::with_capacity(max_depth);
let mut spans = Vec::with_capacity(max_depth);
let mut current = expr;
for _ in 0..max_depth {
- if let ExprKind::MethodCall(path, args, _) = ¤t.kind {
- if args.iter().any(|e| e.span.from_expansion()) {
+ if let ExprKind::MethodCall(path, receiver, args, _) = ¤t.kind {
+ if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
break;
}
method_names.push(path.ident.name);
- arg_lists.push(&**args);
+ arg_lists.push((*receiver, &**args));
spans.push(path.ident.span);
- current = &args[0];
+ current = receiver;
} else {
break;
}
/// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
/// containing the `Expr`s for
/// `.bar()` and `.baz()`
-pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<&'a [Expr<'a>]>> {
+pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
let mut current = expr;
let mut matched = Vec::with_capacity(methods.len());
for method_name in methods.iter().rev() {
// method chains are stored last -> first
- if let ExprKind::MethodCall(path, args, _) = current.kind {
+ if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
if path.ident.name.as_str() == *method_name {
- if args.iter().any(|e| e.span.from_expansion()) {
+ if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
return None;
}
- matched.push(args); // build up `matched` backwards
- current = &args[0]; // go to parent expression
+ matched.push((receiver, args)); // build up `matched` backwards
+ current = receiver; // go to parent expression
} else {
return None;
}
ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
})
},
- ExprKind::MethodCall(_, args, _) => {
- let i = args.iter().position(|arg| arg.hir_id == id)?;
+ ExprKind::MethodCall(_, receiver, args, _) => {
+ let i = std::iter::once(receiver)
+ .chain(args.iter())
+ .position(|arg| arg.hir_id == id)?;
let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
}
};
- let mut expr = &func.value;
+ let mut expr = func.value;
loop {
match expr.kind {
#[rustfmt::skip]
if abort {
return false;
}
- if let ExprKind::MethodCall(seg, [recv], _) = expr.kind {
+ if let ExprKind::MethodCall(seg, recv, [], _) = expr.kind {
if path_to_local_id(recv, id) {
if seg.ident.name.as_str() == "capacity" {
abort = true;
| AssocOp::LessEqual
| AssocOp::NotEqual
| AssocOp::Greater
- | AssocOp::GreaterEqual => format!(
- "{} {} {}",
- lhs,
- op.to_ast_binop().expect("Those are AST ops").to_string(),
- rhs
- ),
+ | AssocOp::GreaterEqual => {
+ format!(
+ "{} {} {}",
+ lhs,
+ op.to_ast_binop().expect("Those are AST ops").to_string(),
+ rhs
+ )
+ },
AssocOp::Assign => format!("{} = {}", lhs, rhs),
AssocOp::AssignOp(op) => {
format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs)
/// indicates whether the function from `parent_expr` takes its args by double reference
fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool {
let ty = match parent_expr.kind {
- ExprKind::MethodCall(_, call_args, _) => {
+ ExprKind::MethodCall(_, receiver, call_args, _) => {
if let Some(sig) = self
.cx
.typeck_results()
.type_dependent_def_id(parent_expr.hir_id)
.map(|did| self.cx.tcx.fn_sig(did).skip_binder())
{
- call_args
- .iter()
+ std::iter::once(receiver)
+ .chain(call_args.iter())
.position(|arg| arg.hir_id == cmt_hir_id)
.map(|i| sig.inputs()[i])
} else {
match &parent_expr.kind {
// given expression is the self argument and will be handled completely by the compiler
// i.e.: `|x| x.is_something()`
- ExprKind::MethodCall(_, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => {
+ ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => {
let _ = write!(self.suggestion_start, "{}{}", start_snip, ident_str_with_proj);
self.next_pos = span.hi();
return;
},
// item is used in a call
// i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)`
- ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, [_, call_args @ ..], _) => {
+ ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [call_args @ ..], _) => {
let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id);
let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind();
helper(typeck, true, arg, f)?;
}
},
- ExprKind::MethodCall(_, args, _) | ExprKind::Tup(args) | ExprKind::Array(args) => {
+ ExprKind::MethodCall(_, receiver, args, _) => {
+ helper(typeck, true, receiver, f)?;
+ for arg in args {
+ helper(typeck, true, arg, f)?;
+ }
+ },
+ ExprKind::Tup(args) | ExprKind::Array(args) => {
for arg in args {
helper(typeck, true, arg, f)?;
}
if match_qpath(qpath, &["char"]);
if let ExprKind::Lit(ref lit) = expr.kind;
if let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node;
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
+ if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
if name.as_str() == "x";
then {
// report your lint here
if let Some(init) = local.init;
if let ExprKind::Lit(ref lit) = init.kind;
if let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node;
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
+ if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
if name.as_str() == "x";
if let StmtKind::Local(local1) = block.stmts[1].kind;
if let Some(init1) = local1.init;
if let ExprKind::Lit(ref lit1) = init1.kind;
if let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node;
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind;
+ if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local1.pat.kind;
if name1.as_str() == "_t";
if let StmtKind::Semi(e) = block.stmts[2].kind;
if let ExprKind::Unary(UnOp::Neg, inner) = e.kind;
if let ExprKind::Path(ref qpath) = func.kind;
if match_qpath(qpath, &["String", "new"]);
if args.is_empty();
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
+ if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
if name.as_str() == "expr";
if let Some(trailing_expr) = block.expr;
if let ExprKind::Call(func1, args1) = trailing_expr.kind;
if_chain! {
if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = pat.kind;
+ if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind;
if name.as_str() == "y";
if let ExprKind::Struct(qpath, fields, None) = arg.kind;
if matches!(qpath, QPath::LangItem(LangItem::Range, _));
if let Some(init) = local.init;
if let ExprKind::Path(ref qpath1) = init.kind;
if match_qpath(qpath1, &["y"]);
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
+ if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind;
if name1.as_str() == "z";
if block.expr.is_none();
then {
if let Some(init1) = local1.init;
if let ExprKind::Lit(ref lit4) = init1.kind;
if let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node;
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local1.pat.kind;
+ if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local1.pat.kind;
if name.as_str() == "x";
if let Some(trailing_expr) = block.expr;
if let ExprKind::Path(ref qpath) = trailing_expr.kind;
if arms[2].guard.is_none();
if let ExprKind::Lit(ref lit5) = arms[2].body.kind;
if let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node;
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
+ if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind;
if name1.as_str() == "a";
then {
// report your lint here
}
}
if_chain! {
- if let ExprKind::MethodCall(method_name, args, _) = expr.kind;
+ if let ExprKind::MethodCall(method_name, receiver, args, _) = expr.kind;
if method_name.ident.as_str() == "test";
- if args.len() == 1;
- if let ExprKind::Path(ref qpath) = args[0].kind;
+ if let ExprKind::Path(ref qpath) = receiver.kind;
if match_qpath(qpath, &["test_method_call"]);
+ if args.is_empty();
then {
// report your lint here
}
edition = "2021"
[dependencies]
-rustdoc = { path = "../../librustdoc" }
+mdbook = { version = "0.4", default-features = false, features = ["search"] }
[[bin]]
name = "error_index_generator"
--- /dev/null
+[book]
+title = "Error codes index"
+description = "Book listing all Rust error codes"
+src = ""
+
+[output.html]
+git-repository-url = "https://github.com/rust-lang/rust/"
+additional-css = ["error-index.css"]
+additional-js = ["error-index.js"]
+
+[output.html.search]
+enable = true
+limit-results = 20
+use-boolean-and = true
+boost-title = 2
+boost-hierarchy = 2
+boost-paragraph = 1
+expand = true
+heading-split-level = 0
--- /dev/null
+code.compile_fail {
+ border-left: 2px solid red;
+}
+
+pre .tooltip {
+ position: absolute;
+ left: -25px;
+ top: 0;
+ z-index: 1;
+ color: red;
+ cursor: pointer;
+}
+pre .tooltip::after {
+ display: none;
+ content: "This example deliberately fails to compile";
+ background-color: #000;
+ color: #fff;
+ border-color: #000;
+ text-align: center;
+ padding: 5px 3px 3px 3px;
+ border-radius: 6px;
+ margin-left: 5px;
+}
+pre .tooltip::before {
+ display: none;
+ border-color: transparent black transparent transparent;
+ content: " ";
+ position: absolute;
+ top: 50%;
+ left: 16px;
+ margin-top: -5px;
+ border-width: 5px;
+ border-style: solid;
+}
+
+pre .tooltip:hover::before, pre .tooltip:hover::after {
+ display: inline;
+}
--- /dev/null
+for (const elem of document.querySelectorAll("pre.playground")) {
+ if (elem.querySelector(".compile_fail") === null) {
+ continue;
+ }
+ const child = document.createElement("div");
+ child.className = "tooltip";
+ child.textContent = "ⓘ";
+ elem.appendChild(child);
+}
#![feature(rustc_private)]
extern crate rustc_driver;
-extern crate rustc_span;
+// We use the function we generate from `register_diagnostics!`.
use crate::error_codes::error_codes;
use std::env;
use std::error::Error;
-use std::fs::{create_dir_all, File};
+use std::fs::{self, File};
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
-use rustc_span::edition::DEFAULT_EDITION;
+use std::str::FromStr;
-use rustdoc::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
+use mdbook::book::{parse_summary, BookItem, Chapter};
+use mdbook::{Config, MDBook};
macro_rules! register_diagnostics {
($($error_code:ident: $message:expr,)+ ; $($undocumented:ident,)* ) => {
mod error_codes;
enum OutputFormat {
- HTML(HTMLFormatter),
+ HTML,
Markdown,
Unknown(String),
}
impl OutputFormat {
- fn from(format: &str, resource_suffix: &str) -> OutputFormat {
+ fn from(format: &str) -> OutputFormat {
match &*format.to_lowercase() {
- "html" => OutputFormat::HTML(HTMLFormatter(resource_suffix.to_owned())),
+ "html" => OutputFormat::HTML,
"markdown" => OutputFormat::Markdown,
s => OutputFormat::Unknown(s.to_owned()),
}
}
}
-struct HTMLFormatter(String);
-
-impl HTMLFormatter {
- fn create_error_code_file(
- &self,
- err_code: &str,
- explanation: &str,
- parent_dir: &Path,
- ) -> Result<(), Box<dyn Error>> {
- let mut output_file = File::create(parent_dir.join(err_code).with_extension("html"))?;
-
- self.header(&mut output_file, "../", "")?;
- self.title(&mut output_file, &format!("Error code {}", err_code))?;
-
- let mut id_map = IdMap::new();
- let playground =
- Playground { crate_name: None, url: String::from("https://play.rust-lang.org/") };
- write!(
- output_file,
- "{}",
- Markdown {
- content: explanation,
- links: &[],
- ids: &mut id_map,
- error_codes: ErrorCodes::Yes,
- edition: DEFAULT_EDITION,
- playground: &Some(playground),
- heading_offset: HeadingOffset::H1,
- }
- .into_string()
- )?;
- write!(
- output_file,
- "<p>\
- <a style='text-align: center;display: block;width: 100%;' \
- href='../error-index.html'>Back to list of error codes</a>\
- </p>",
- )?;
-
- self.footer(&mut output_file)
- }
-
- fn header(
- &self,
- output: &mut dyn Write,
- extra_path: &str,
- extra: &str,
- ) -> Result<(), Box<dyn Error>> {
- write!(
- output,
- r##"<!DOCTYPE html>
-<html>
-<head>
-<title>Rust Compiler Error Index</title>
-<meta charset="utf-8">
-<!-- Include rust.css after light.css so its rules take priority. -->
-<link rel="stylesheet" type="text/css" href="{extra_path}rustdoc{suffix}.css"/>
-<link rel="stylesheet" type="text/css" href="{extra_path}light{suffix}.css"/>
-<link rel="stylesheet" type="text/css" href="{extra_path}rust.css"/>
-<style>
-.error-undescribed {{
- display: none;
-}}
-</style>{extra}
-</head>
-<body>
-"##,
- suffix = self.0,
- )?;
- Ok(())
- }
-
- fn title(&self, output: &mut dyn Write, title: &str) -> Result<(), Box<dyn Error>> {
- write!(output, "<h1>{}</h1>\n", title)?;
- Ok(())
- }
-
- fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
- write!(output, "</body></html>")?;
- Ok(())
- }
-}
-
/// Output an HTML page for the errors in `err_map` to `output_path`.
fn render_markdown(output_path: &Path) -> Result<(), Box<dyn Error>> {
let mut output_file = File::create(output_path)?;
Ok(())
}
-fn render_html(output_path: &Path, formatter: HTMLFormatter) -> Result<(), Box<dyn Error>> {
- let mut output_file = File::create(output_path)?;
+// By default, mdbook doesn't consider code blocks as Rust ones contrary to rustdoc so we have
+// to manually add `rust` attribute whenever needed.
+fn add_rust_attribute_on_codeblock(explanation: &str) -> String {
+ // Very hacky way to add the rust attribute on all code blocks.
+ let mut skip = true;
+ explanation.split("\n```").fold(String::new(), |mut acc, part| {
+ if !acc.is_empty() {
+ acc.push_str("\n```");
+ }
+ if !skip {
+ if let Some(attrs) = part.split('\n').next() {
+ if !attrs.contains("rust")
+ && (attrs.is_empty()
+ || attrs.contains("compile_fail")
+ || attrs.contains("ignore")
+ || attrs.contains("edition"))
+ {
+ if !attrs.is_empty() {
+ acc.push_str("rust,");
+ } else {
+ acc.push_str("rust");
+ }
+ }
+ }
+ }
+ skip = !skip;
+ acc.push_str(part);
+ acc
+ })
+}
- let error_codes_dir = "error_codes";
+fn render_html(output_path: &Path) -> Result<(), Box<dyn Error>> {
+ let mut introduction = format!(
+ "<script src='redirect.js'></script>
+# Rust error codes index
- let parent = output_path.parent().expect("There should have a parent").join(error_codes_dir);
+This page lists all the error codes emitted by the Rust compiler.
- if !parent.exists() {
- create_dir_all(&parent)?;
- }
+"
+ );
- formatter.header(
- &mut output_file,
- "",
- &format!(
- r#"<script>(function() {{
- if (window.location.hash) {{
- let code = window.location.hash.replace(/^#/, '');
- // We have to make sure this pattern matches to avoid inadvertently creating an
- // open redirect.
- if (/^E[0-9]+$/.test(code)) {{
- window.location = './{error_codes_dir}/' + code + '.html';
- }}
- }}
-}})()</script>"#
- ),
- )?;
- formatter.title(&mut output_file, "Rust Compiler Error Index")?;
+ let err_codes = error_codes();
+ let mut chapters = Vec::with_capacity(err_codes.len());
- write!(
- output_file,
- "<p>This page lists all the error codes emitted by the Rust compiler. If you want a full \
- explanation on an error code, click on it.</p>\
- <ul>",
- )?;
- for (err_code, explanation) in error_codes().iter() {
+ for (err_code, explanation) in err_codes.iter() {
if let Some(explanation) = explanation {
- write!(
- output_file,
- "<li><a href='./{0}/{1}.html'>{1}</a></li>",
- error_codes_dir, err_code
- )?;
- formatter.create_error_code_file(err_code, explanation, &parent)?;
+ introduction.push_str(&format!(" * [{0}](./{0}.html)\n", err_code));
+
+ let content = add_rust_attribute_on_codeblock(explanation);
+ chapters.push(BookItem::Chapter(Chapter {
+ name: err_code.to_string(),
+ content: format!("# Error code {}\n\n{}\n", err_code, content),
+ number: None,
+ sub_items: Vec::new(),
+ // We generate it into the `error_codes` folder.
+ path: Some(PathBuf::from(&format!("{}.html", err_code))),
+ source_path: None,
+ parent_names: Vec::new(),
+ }));
} else {
- write!(output_file, "<li>{}</li>", err_code)?;
+ introduction.push_str(&format!(" * {}\n", err_code));
}
}
- write!(output_file, "</ul>")?;
- formatter.footer(&mut output_file)
+
+ let mut config = Config::from_str(include_str!("book_config.toml"))?;
+ config.build.build_dir = output_path.join("error_codes").to_path_buf();
+ let mut book = MDBook::load_with_config_and_summary(
+ env!("CARGO_MANIFEST_DIR"),
+ config,
+ parse_summary("")?,
+ )?;
+ let chapter = Chapter {
+ name: "Rust error codes index".to_owned(),
+ content: introduction,
+ number: None,
+ sub_items: chapters,
+ // Very important: this file is named as `error-index.html` and not `index.html`!
+ path: Some(PathBuf::from("error-index.html")),
+ source_path: None,
+ parent_names: Vec::new(),
+ };
+ book.book.sections.push(BookItem::Chapter(chapter));
+ book.build()?;
+
+ // We can't put this content into another file, otherwise `mbdbook` will also put it into the
+ // output directory, making a duplicate.
+ fs::write(
+ output_path.join("error-index.html"),
+ r#"<!DOCTYPE html>
+<html>
+ <head>
+ <title>Rust error codes index - Error codes index</title>
+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+ <meta name="description" content="Book listing all Rust error codes">
+ <script src="error_codes/redirect.js"></script>
+ </head>
+ <body>
+ <div>If you are not automatically redirected to the error code index, please <a id="index-link" href="./error_codes/error-index.html">here</a>.
+ <script>document.getElementById("index-link").click()</script>
+ </body>
+</html>"#,
+ )?;
+
+ // No need for a 404 file, it's already handled by the server.
+ fs::remove_file(output_path.join("error_codes/404.html"))?;
+
+ Ok(())
}
fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> {
match format {
OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
- OutputFormat::HTML(h) => render_html(dst, h),
+ OutputFormat::HTML => render_html(dst),
OutputFormat::Markdown => render_markdown(dst),
}
}
let mut args = env::args().skip(1);
let format = args.next();
let dst = args.next();
- let resource_suffix = args.next().unwrap_or_else(String::new);
- let format = format
- .map(|a| OutputFormat::from(&a, &resource_suffix))
- .unwrap_or(OutputFormat::from("html", &resource_suffix));
+ let format = format.map(|a| OutputFormat::from(&a)).unwrap_or(OutputFormat::from("html"));
let dst = dst.map(PathBuf::from).unwrap_or_else(|| match format {
- OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"),
+ OutputFormat::HTML => PathBuf::from("doc"),
OutputFormat::Markdown => PathBuf::from("doc/error-index.md"),
OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
});
fn main() {
rustc_driver::init_env_logger("RUST_LOG");
let (format, dst) = parse_args();
- let result =
- rustc_span::create_default_session_globals_then(move || main_with_result(format, &dst));
+ let result = main_with_result(format, &dst);
if let Err(e) = result {
- panic!("{}", e.to_string());
+ panic!("{:?}", e);
}
}
--- /dev/null
+(function() {
+ if (window.location.hash) {
+ let code = window.location.hash.replace(/^#/, '');
+ // We have to make sure this pattern matches to avoid inadvertently creating an
+ // open redirect.
+ if (!/^E[0-9]+$/.test(code)) {
+ return;
+ }
+ if (window.location.pathname.indexOf("/error_codes/") !== -1) {
+ // We're not at the top level, so we don't prepend with "./error_codes/".
+ window.location = './' + code + '.html';
+ } else {
+ window.location = './error_codes/' + code + '.html';
+ }
+ }
+})()
/// Descriptions of rustc lint groups.
static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
("unused", "Lints that detect things being declared but not used, or excess syntax"),
+ ("let-underscore", "Lints that detect wildcard let bindings that are likely to be invalid"),
("rustdoc", "Rustdoc-specific lints"),
("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"),
("nonstandard-style", "Violation of standard naming conventions"),
//! make gcc/clang pass `-flavor <flavor>` as the first two arguments in the linker invocation
//! and since Windows does not support symbolic links for files this wrapper is used in place of a
//! symbolic link. It execs `../rust-lld -flavor <flavor>` by propagating the flavor argument
-//! passed to the wrapper as the first two arguments. On Windows it spawns a `..\rust-lld.exe`
-//! child process.
+//! obtained from the wrapper's name as the first two arguments.
+//! On Windows it spawns a `..\rust-lld.exe` child process.
use std::fmt::Display;
use std::path::{Path, PathBuf};
rust_lld_path
}
+/// Extract LLD flavor name from the lld-wrapper executable name.
+fn get_lld_flavor(current_exe_path: &Path) -> Result<&'static str, String> {
+ let stem = current_exe_path.file_stem();
+ Ok(match stem.and_then(|s| s.to_str()) {
+ Some("ld.lld") => "gnu",
+ Some("ld64.lld") => "darwin",
+ Some("lld-link") => "link",
+ Some("wasm-ld") => "wasm",
+ _ => return Err(format!("{:?}", stem)),
+ })
+}
+
/// Returns the command for invoking rust-lld with the correct flavor.
-/// LLD only accepts the flavor argument at the first two arguments, so move it there.
+/// LLD only accepts the flavor argument at the first two arguments, so pass it there.
///
/// Exits on error.
fn get_rust_lld_command(current_exe_path: &Path) -> process::Command {
let rust_lld_path = get_rust_lld_path(current_exe_path);
let mut command = process::Command::new(rust_lld_path);
- let mut flavor = None;
- let args = env::args_os()
- .skip(1)
- .filter(|arg| match arg.to_str().and_then(|s| s.strip_prefix("-rustc-lld-flavor=")) {
- Some(suffix) => {
- flavor = Some(suffix.to_string());
- false
- }
- None => true,
- })
- .collect::<Vec<_>>();
+ let flavor =
+ get_lld_flavor(current_exe_path).unwrap_or_exit_with("executable has unexpected name");
command.arg("-flavor");
- command.arg(flavor.unwrap_or_exit_with("-rustc-lld-flavor=<flavor> is not passed"));
- command.args(args);
+ command.arg(flavor);
+ command.args(env::args_os().skip(1));
command
}
-Subproject commit ab88e64b152d3704c35db96dbbc6efaaed67773f
+Subproject commit dba35d2be72f4b78343d1a0f0b4737306f310672
walk::filter_dirs(path)
// We exempt these as they require the placeholder
// for their operation
- || path.ends_with("compiler/rustc_passes/src/lib_features.rs")
+ || path.ends_with("compiler/rustc_attr/src/builtin.rs")
|| path.ends_with("src/tools/tidy/src/features/version.rs")
|| path.ends_with("src/tools/replace-version-placeholder")
},
curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true }
# Ensure default features of libz-sys, which are disabled in some scenarios.
libz-sys = { version = "1.1.2" }
-# The only user of memchr's deprecated `use_std` feature is `combine`, so this can be
-# removed if/when https://github.com/Marwes/combine/pull/348 is merged and released.
-memchr = { version = "2.5", features = ["std", "use_std"] }
# Ensure default features of regex, which are disabled in some scenarios.
regex = { version = "1.5.6" }
serde_json = { version = "1.0.31", features = ["raw_value", "unbounded_depth"] }
-use rustc_ast::ast::{self, BindingMode, Pat, PatField, PatKind, RangeEnd, RangeSyntax};
+use rustc_ast::ast::{
+ self, BindingAnnotation, ByRef, Pat, PatField, PatKind, RangeEnd, RangeSyntax,
+};
use rustc_ast::ptr;
use rustc_span::{BytePos, Span};
write_list(&items, &fmt)
}
PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape),
- PatKind::Ident(binding_mode, ident, ref sub_pat) => {
- let (prefix, mutability) = match binding_mode {
- BindingMode::ByRef(mutability) => ("ref", mutability),
- BindingMode::ByValue(mutability) => ("", mutability),
+ PatKind::Ident(BindingAnnotation(by_ref, mutability), ident, ref sub_pat) => {
+ let prefix = match by_ref {
+ ByRef::Yes => "ref",
+ ByRef::No => "",
};
let mut_infix = format_mutability(mutability).trim();
let id_str = rewrite_ident(context, ident);
"autocfg",
"bitflags",
"block-buffer",
- "block-padding",
- "byte-tools",
- "byteorder",
"cc",
"cfg-if",
"chalk-derive",
"ena",
"env_logger",
"expect-test",
- "fake-simd",
"fallible-iterator", // dependency of `thorin`
"filetime",
"fixedbitset",
"object",
"odht",
"once_cell",
- "opaque-debug",
"parking_lot",
"parking_lot_core",
"pathdiff",
+#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
#[inline(always)]
-fn bitset_search<
+const fn bitset_search<
const N: usize,
const CHUNK_SIZE: usize,
const N1: usize,
let bucket_idx = (needle / 64) as usize;
let chunk_map_idx = bucket_idx / CHUNK_SIZE;
let chunk_piece = bucket_idx % CHUNK_SIZE;
- let chunk_idx = if let Some(&v) = chunk_idx_map.get(chunk_map_idx) {
- v
+ // FIXME: const-hack: Revert to `slice::get` after `const_slice_index`
+ // feature stabilizes.
+ let chunk_idx = if chunk_map_idx < chunk_idx_map.len() {
+ chunk_idx_map[chunk_map_idx]
} else {
return false;
};
let idx = bitset_chunk_idx[chunk_idx as usize][chunk_piece] as usize;
- let word = if let Some(word) = bitset_canonical.get(idx) {
- *word
+ // FIXME: const-hack: Revert to `slice::get` after `const_slice_index`
+ // feature stabilizes.
+ let word = if idx < bitset_canonical.len() {
+ bitset_canonical[idx]
} else {
let (real_idx, mapping) = bitset_canonicalized[idx - bitset_canonical.len()];
let mut word = bitset_canonical[real_idx as usize];
writeln!(
&mut self.file,
- "static BITSET_CANONICAL: [u64; {}] = [{}];",
+ "const BITSET_CANONICAL: &'static [u64; {}] = &[{}];",
canonicalized.canonical_words.len(),
fmt_list(canonicalized.canonical_words.iter().map(|v| Bits(*v))),
)
self.bytes_used += 8 * canonicalized.canonical_words.len();
writeln!(
&mut self.file,
- "static BITSET_MAPPING: [(u8, u8); {}] = [{}];",
+ "const BITSET_MAPPING: &'static [(u8, u8); {}] = &[{}];",
canonicalized.canonicalized_words.len(),
fmt_list(&canonicalized.canonicalized_words),
)
self.blank_line();
- writeln!(&mut self.file, "pub fn lookup(c: char) -> bool {{").unwrap();
+ writeln!(
+ &mut self.file,
+ r#"#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]"#
+ )
+ .unwrap();
+ writeln!(&mut self.file, "pub const fn lookup(c: char) -> bool {{").unwrap();
writeln!(&mut self.file, " super::bitset_search(",).unwrap();
writeln!(&mut self.file, " c as u32,").unwrap();
writeln!(&mut self.file, " &BITSET_CHUNKS_MAP,").unwrap();
writeln!(
&mut self.file,
- "static BITSET_CHUNKS_MAP: [u8; {}] = [{}];",
+ "const BITSET_CHUNKS_MAP: &'static [u8; {}] = &[{}];",
chunk_indices.len(),
fmt_list(&chunk_indices),
)
self.bytes_used += chunk_indices.len();
writeln!(
&mut self.file,
- "static BITSET_INDEX_CHUNKS: [[u8; {}]; {}] = [{}];",
+ "const BITSET_INDEX_CHUNKS: &'static [[u8; {}]; {}] = &[{}];",
chunk_length,
chunks.len(),
fmt_list(chunks.iter()),
"compiler/rustc_macros/src/diagnostics"
]
+[autolabel."A-query-system"]
+trigger_files = [
+ "compiler/rustc_query_system",
+ "compiler/rustc_query_impl",
+ "compiler/rustc_macros/src/query.rs"
+]
+
[notify-zulip."I-prioritize"]
zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
topic = "#{number} {title}"
* Changing observable runtime behavior of library APIs
"""
-[mentions."library/proc_macro/src/bridge"]
-cc = ["@rust-lang/wg-rls-2"]
-
[mentions."src/librustdoc/clean/types.rs"]
cc = ["@camelid"]