[[package]]
name = "bitflags"
-version = "1.2.1"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitmaps"
[[package]]
name = "memchr"
-version = "2.4.1"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
[[package]]
name = "pulldown-cmark"
-version = "0.9.1"
+version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
+checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63"
dependencies = [
"bitflags",
"memchr",
debug!(?self.captured_lifetimes);
let name = match res {
LifetimeRes::Param { mut param, binder } => {
- debug_assert_ne!(ident.name, kw::UnderscoreLifetime);
let p_name = ParamName::Plain(ident);
if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
if !captured_lifetimes.binders_to_ignore.contains(&binder) {
/// `#[unstable]`
Unstable {
/// Reason for the current stability level.
- reason: Option<Symbol>,
+ reason: UnstableReason,
/// Relevant `rust-lang/rust` issue.
issue: Option<NonZeroU32>,
is_soft: bool,
}
}
+#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
+#[derive(HashStable_Generic)]
+pub enum UnstableReason {
+ None,
+ Default,
+ Some(Symbol),
+}
+
+impl UnstableReason {
+ fn from_opt_reason(reason: Option<Symbol>) -> Self {
+ // UnstableReason::Default constructed manually
+ match reason {
+ Some(r) => Self::Some(r),
+ None => Self::None,
+ }
+ }
+
+ pub fn to_opt_reason(&self) -> Option<Symbol> {
+ match self {
+ Self::None => None,
+ Self::Default => Some(sym::unstable_location_reason_default),
+ Self::Some(r) => Some(*r),
+ }
+ }
+}
+
/// Collects stability info from all stability attributes in `attrs`.
/// Returns `None` if no stability attributes are found.
pub fn find_stability(
);
continue;
}
- let level = Unstable { reason, issue: issue_num, is_soft, implied_by };
+ let level = Unstable {
+ reason: UnstableReason::from_opt_reason(reason),
+ issue: issue_num,
+ is_soft,
+ implied_by,
+ };
if sym::unstable == meta_name {
stab = Some((Stability { level, feature }, attr.span));
} else {
span: Span,
/// The hidden type.
hidden_ty: Ty<'tcx>,
+ /// The opaque type.
+ key: ty::OpaqueTypeKey<'tcx>,
/// The unexpected region.
member_region: ty::Region<'tcx>,
},
}
}
- RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => {
+ RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, key, member_region } => {
let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
+ let named_key = self.regioncx.name_regions(self.infcx.tcx, key);
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
self.buffer_error(unexpected_hidden_region_diagnostic(
self.infcx.tcx,
span,
named_ty,
named_region,
+ named_key,
));
}
debug!("trait spans found: {:?}", traits);
for span in &traits {
let mut multi_span: MultiSpan = vec![*span].into();
- multi_span.push_span_label(
- *span,
- "this has an implicit `'static` lifetime requirement".to_string(),
- );
+ multi_span
+ .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
multi_span.push_span_label(
ident.span,
- "calling this method introduces the `impl`'s 'static` requirement".to_string(),
+ "calling this method introduces the `impl`'s 'static` requirement",
);
err.span_note(multi_span, "the used `impl` has a `'static` requirement");
err.span_suggestion_verbose(
/// The hidden type in which `R0` appears. (Used in error reporting.)
pub(crate) hidden_ty: Ty<'tcx>,
+ pub(crate) key: ty::OpaqueTypeKey<'tcx>,
+
/// The region `R0`.
pub(crate) member_region_vid: ty::RegionVid,
member_region_vid,
definition_span: m_c.definition_span,
hidden_ty: m_c.hidden_ty,
+ key: m_c.key,
start_index,
end_index,
});
errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion {
span: m_c.definition_span,
hidden_ty: m_c.hidden_ty,
+ key: m_c.key,
member_region,
});
}
// after producing an error for each of them.
let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
self.tcx,
- def_id,
+ opaque_type_key,
map,
instantiated_ty.ty,
instantiated_ty.span,
struct ReverseMapper<'tcx> {
tcx: TyCtxt<'tcx>,
- opaque_type_def_id: LocalDefId,
+ key: ty::OpaqueTypeKey<'tcx>,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
map_missing_regions_to_empty: bool,
impl<'tcx> ReverseMapper<'tcx> {
fn new(
tcx: TyCtxt<'tcx>,
- opaque_type_def_id: LocalDefId,
+ key: ty::OpaqueTypeKey<'tcx>,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
hidden_ty: Ty<'tcx>,
span: Span,
) -> Self {
Self {
tcx,
- opaque_type_def_id,
+ key,
map,
map_missing_regions_to_empty: false,
hidden_ty: Some(hidden_ty),
}
}
- let generics = self.tcx().generics_of(self.opaque_type_def_id);
+ let generics = self.tcx().generics_of(self.key.def_id);
match self.map.get(&r.into()).map(|k| k.unpack()) {
Some(GenericArgKind::Lifetime(r1)) => r1,
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
if let Some(hidden_ty) = self.hidden_ty.take() {
unexpected_hidden_region_diagnostic(
self.tcx,
- self.tcx.def_span(self.opaque_type_def_id),
+ self.tcx.def_span(self.key.def_id),
hidden_ty,
r,
+ self.key,
)
.emit();
}
use rustc_infer::infer::{
InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin,
};
-use rustc_infer::traits::ObligationCause;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::AssertKind;
)
.unwrap();
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
- // Check that RPITs are only constrained in their outermost
- // function, otherwise report a mismatched types error.
- if let OpaqueTyOrigin::FnReturn(parent) | OpaqueTyOrigin::AsyncFn(parent)
- = infcx.opaque_ty_origin_unchecked(opaque_type_key.def_id, hidden_type.span)
- && parent.to_def_id() != body.source.def_id()
- {
- infcx
- .report_mismatched_types(
- &ObligationCause::misc(
- hidden_type.span,
- infcx.tcx.hir().local_def_id_to_hir_id(
- body.source.def_id().expect_local(),
- ),
- ),
- infcx.tcx.mk_opaque(opaque_type_key.def_id.to_def_id(), opaque_type_key.substs),
- hidden_type.ty,
- ty::error::TypeError::Mismatch,
- )
- .emit();
- }
trace!(
"finalized opaque type {:?} to {:#?}",
opaque_type_key,
{
// source for rustc_* is not included in the rust-src component; disable the errors about this
"rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"],
- "rust-analyzer.assist.importGranularity": "module",
- "rust-analyzer.assist.importEnforceGranularity": true,
- "rust-analyzer.assist.importPrefix": "crate",
- "rust-analyzer.cargo.runBuildScripts": true,
+ "rust-analyzer.imports.granularity.enforce": true,
+ "rust-analyzer.imports.granularity.group": "module",
+ "rust-analyzer.imports.prefix": "crate",
"rust-analyzer.cargo.features": ["unstable-features"],
"rust-analyzer.linkedProjects": [
"./Cargo.toml",
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "ahash"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+dependencies = [
+ "getrandom",
+ "once_cell",
+ "version_check",
+]
+
[[package]]
name = "anyhow"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
[[package]]
name = "cfg-if"
version = "1.0.0"
[[package]]
name = "cranelift-bforest"
-version = "0.83.0"
+version = "0.85.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed44413e7e2fe3260d0ed73e6956ab188b69c10ee92b892e401e0f4f6808c68b"
+checksum = "749d0d6022c9038dccf480bdde2a38d435937335bf2bb0f14e815d94517cdce8"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
-version = "0.83.0"
+version = "0.85.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b5d83f0f26bf213f971f45589d17e5b65e4861f9ed22392b0cbb6eaa5bd329c"
+checksum = "e94370cc7b37bf652ccd8bb8f09bd900997f7ccf97520edfc75554bb5c4abbea"
dependencies = [
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
"cranelift-entity",
+ "cranelift-isle",
"gimli",
"log",
- "regalloc",
+ "regalloc2",
"smallvec",
"target-lexicon",
]
[[package]]
name = "cranelift-codegen-meta"
-version = "0.83.0"
+version = "0.85.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6800dc386177df6ecc5a32680607ed8ba1fa0d31a2a59c8c61fbf44826b8191d"
+checksum = "e0a3cea8fdab90e44018c5b9a1dfd460d8ee265ac354337150222a354628bdb6"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
-version = "0.83.0"
+version = "0.85.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c961f85070985ebc8fcdb81b838a5cf842294d1e6ed4852446161c7e246fd455"
+checksum = "5ac72f76f2698598951ab26d8c96eaa854810e693e7dd52523958b5909fde6b2"
[[package]]
name = "cranelift-entity"
-version = "0.83.0"
+version = "0.85.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2347b2b8d1d5429213668f2a8e36c85ee3c73984a2f6a79007e365d3e575e7ed"
+checksum = "09eaeacfcd2356fe0e66b295e8f9d59fdd1ac3ace53ba50de14d628ec902f72d"
[[package]]
name = "cranelift-frontend"
-version = "0.83.0"
+version = "0.85.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cbcdbf7bed29e363568b778649b69dabc3d727256d5d25236096ef693757654"
+checksum = "dba69c9980d5ffd62c18a2bde927855fcd7c8dc92f29feaf8636052662cbd99c"
dependencies = [
"cranelift-codegen",
"log",
"target-lexicon",
]
+[[package]]
+name = "cranelift-isle"
+version = "0.85.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2920dc1e05cac40304456ed3301fde2c09bd6a9b0210bcfa2f101398d628d5b"
+
[[package]]
name = "cranelift-jit"
-version = "0.83.0"
+version = "0.85.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c769d4e0d76f59c8b2a3bf0477d89ee149bb0731b53fbb245ee081d49063095"
+checksum = "1c3c5ed067f2c81577e431f3039148a9c187b33cc79e0d1731fede27d801ec56"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "cranelift-module"
-version = "0.83.0"
+version = "0.85.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ab57d399a2401074bb0cc40b3031e420f3d66d46ec0cf21eeae53ac04bd73e2"
+checksum = "eee6784303bf9af235237a4885f7417e09a35df896d38ea969a0081064b3ede4"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "cranelift-native"
-version = "0.83.0"
+version = "0.85.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f4cdf93552e5ceb2e3c042829ebb4de4378492705f769eadc6a7c6c5251624c"
+checksum = "f04dfa45f9b2a6f587c564d6b63388e00cd6589d2df6ea2758cf79e1a13285e6"
dependencies = [
"cranelift-codegen",
"libc",
[[package]]
name = "cranelift-object"
-version = "0.83.0"
+version = "0.85.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf8e65f4839c26e6237fc0744911d79b0a2ac5e76b4e4eebd14db2b8d849fd31"
+checksum = "0bf38b2c505db749276793116c0cb30bd096206c7810e471677a453134881881"
dependencies = [
"anyhow",
"cranelift-codegen",
"cfg-if",
]
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
[[package]]
name = "gimli"
version = "0.26.1"
"indexmap",
]
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+dependencies = [
+ "ahash",
+]
+
[[package]]
name = "hashbrown"
version = "0.12.3"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [
"autocfg",
- "hashbrown",
+ "hashbrown 0.12.3",
]
[[package]]
name = "libc"
-version = "0.2.119"
+version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
+checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "libloading"
[[package]]
name = "object"
-version = "0.27.1"
+version = "0.28.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
+checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
dependencies = [
"crc32fast",
+ "hashbrown 0.11.2",
"indexmap",
"memchr",
]
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
-name = "regalloc"
-version = "0.0.34"
+name = "regalloc2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02"
+checksum = "4a8d23b35d7177df3b9d31ed8a9ab4bf625c668be77a319d4f5efd4a5257701c"
dependencies = [
+ "fxhash",
"log",
- "rustc-hash",
+ "slice-group-by",
"smallvec",
]
"winapi",
]
-[[package]]
-name = "rustc-hash"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
-
[[package]]
name = "rustc_codegen_cranelift"
version = "0.1.0"
"target-lexicon",
]
+[[package]]
+name = "slice-group-by"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec"
+
[[package]]
name = "smallvec"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1"
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
[[package]]
name = "winapi"
version = "0.3.9"
[dependencies]
# These have to be in sync with each other
-cranelift-codegen = { version = "0.83.0", features = ["unwind", "all-arch"] }
-cranelift-frontend = "0.83.0"
-cranelift-module = "0.83.0"
-cranelift-native = "0.83.0"
-cranelift-jit = { version = "0.83.0", optional = true }
-cranelift-object = "0.83.0"
+cranelift-codegen = { version = "0.85.3", features = ["unwind", "all-arch"] }
+cranelift-frontend = "0.85.3"
+cranelift-module = "0.85.3"
+cranelift-native = "0.85.3"
+cranelift-jit = { version = "0.85.3", optional = true }
+cranelift-object = "0.85.3"
target-lexicon = "0.12.0"
gimli = { version = "0.26.0", default-features = false, features = ["write"]}
-object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
+object = { version = "0.28.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
indexmap = "1.9.1"
[[package]]
name = "compiler_builtins"
-version = "0.1.72"
+version = "0.1.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afdbb35d279238cf77f0c9e8d90ad50d6c7bff476ab342baafa29440f0f10bff"
+checksum = "c6e3183e88f659a862835db8f4b67dbeed3d93e44dd4927eef78edb1c149d784"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "hashbrown"
-version = "0.12.1"
+version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
[[package]]
name = "hermit-abi"
-version = "0.2.0"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab7905ea95c6d9af62940f9d7dd9596d54c334ae2c15300c482051292d5637f"
+checksum = "7668753748e445859e4e373c3d41117235d9feed578392f5a3a73efdc751ca4a"
dependencies = [
"compiler_builtins",
"libc",
+ "rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "libc"
-version = "0.2.125"
+version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
+checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
dependencies = [
"rustc-std-workspace-core",
]
{
let entry = entry.unwrap();
if let Some(ext) = entry.path().extension() {
- if ext == "rmeta" || ext == "d" || ext == "dSYM" {
+ if ext == "rmeta" || ext == "d" || ext == "dSYM" || ext == "clif" {
continue;
}
} else {
#[lang = "panic"]
#[track_caller]
-pub fn panic(_msg: &str) -> ! {
+pub fn panic(_msg: &'static str) -> ! {
unsafe {
libc::puts("Panicking\n\0" as *const str as *const i8);
intrinsics::abort();
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
-pub struct NonNull<T: ?Sized>(pub *mut T);
+pub struct NonNull<T: ?Sized>(pub *const T);
impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
}
}
-impl<T> Deref for Box<T> {
+impl<T: ?Sized> Deref for Box<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
return_u128_pair();
}
+#[repr(C)]
+pub struct bool_11 {
+ field0: bool,
+ field1: bool,
+ field2: bool,
+ field3: bool,
+ field4: bool,
+ field5: bool,
+ field6: bool,
+ field7: bool,
+ field8: bool,
+ field9: bool,
+ field10: bool,
+}
+
+extern "C" fn bool_struct_in_11(arg0: bool_11) {}
+
#[allow(unreachable_code)] // FIXME false positive
fn main() {
take_unique(Unique {
call_return_u128_pair();
+ bool_struct_in_11(bool_11 {
+ field0: true,
+ field1: true,
+ field2: true,
+ field3: true,
+ field4: true,
+ field5: true,
+ field6: true,
+ field7: true,
+ field8: true,
+ field9: true,
+ field10: true,
+ });
+
let slice = &[0, 1] as &[i32];
let slice_ptr = slice as *const [i32] as *const i32;
static REF1: &u8 = &42;
static REF2: &u8 = REF1;
assert_eq!(*REF1, *REF2);
+
+ extern "C" {
+ type A;
+ }
+
+ fn main() {
+ let x: &A = unsafe { &*(1usize as *const A) };
+
+ assert_eq!(unsafe { intrinsics::size_of_val(x) }, 0);
+ assert_eq!(unsafe { intrinsics::min_align_of_val(x) }, 1);
+}
}
#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
0 => loop {},
v => panic(v),
};
+
+ if black_box(false) {
+ // Based on https://github.com/rust-lang/rust/blob/2f320a224e827b400be25966755a621779f797cc/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs
+ let _ = Foo::<dyn Send>::new();
+
+ #[allow(dead_code)]
+ struct Foo<T: ?Sized> {
+ base: Never,
+ value: T,
+ }
+
+ impl<T: ?Sized> Foo<T> {
+ pub fn new() -> Box<Foo<T>> {
+ todo!()
+ }
+ }
+
+ enum Never {}
+ }
}
fn panic(_: u128) {
[toolchain]
-channel = "nightly-2022-05-15"
+channel = "nightly-2022-07-25"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 8431aa7b818..a3ff7e68ce5 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
-@@ -3489,11 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
- .join("library");
- normalize_path(&src_dir, "$(echo '$SRC_DIR')");
+@@ -3489,12 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
+ let compiler_src_dir = base_dir.join("compiler");
+ normalize_path(&compiler_src_dir, "$(echo '$COMPILER_DIR')");
- if let Some(virtual_rust_source_base_dir) =
- option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
- {
- normalize_path(&virtual_rust_source_base_dir.join("library"), "$(echo '$SRC_DIR')");
+- normalize_path(&virtual_rust_source_base_dir.join("compiler"), "$(echo '$COMPILER_DIR')");
- }
+ normalize_path(&Path::new("$(cd ../build_sysroot/sysroot_src/library; pwd)"), "$(echo '$SRC_DIR')");
verbose-tests = false
EOF
popd
+
+# FIXME remove once inline asm is fully supported
+export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc"
rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte
rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same
rm src/test/ui/generator/size-moved-locals.rs # same
+rm -r src/test/ui/macros/rfc-2011-nicer-assert-messages/
# vendor intrinsics
rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected
rm src/test/ui/target-feature/missing-plusminus.rs # error not implemented
rm src/test/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
rm -r src/test/run-make/emit-named-files # requires full --emit support
+rm src/test/ui/abi/stack-probes.rs # stack probes not yet implemented
# optimization tests
# ==================
-rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations
+rm src/test/ui/codegen/issue-28950.rs # depends on stack size optimizations
rm src/test/ui/codegen/init-large-type.rs # same
+rm src/test/ui/issues/issue-40883.rs # same
rm -r src/test/run-make/fmt-write-bloat/ # tests an optimization
# backend specific tests
rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
rm -r src/test/run-make/unstable-flag-required # same
rm -r src/test/run-make/rustdoc-* # same
+rm -r src/test/run-make/issue-88756-default-output # same
+rm -r src/test/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
# genuine bugs
# ============
rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
-rm -r src/test/ui/polymorphization/ # polymorphization not yet supported
-rm src/test/codegen-units/polymorphization/unused_type_parameters.rs # same
-
rm src/test/incremental/spike-neg1.rs # errors out for some reason
rm src/test/incremental/spike-neg2.rs # same
rm src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
rm src/test/ui/empty_global_asm.rs # TODO add needs-asm-support
rm src/test/ui/simple_global_asm.rs # TODO add needs-asm-support
rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
+# not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason
+rm -r src/test/run-make/native-link-modifier-bundle
echo "[TEST] rustc test suite"
RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
mod pass_mode;
mod returning;
+use cranelift_module::ModuleError;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_target::abi::call::{Conv, FnAbi};
) -> FuncId {
let name = tcx.symbol_name(inst).name;
let sig = get_function_sig(tcx, module.isa().triple(), inst);
- module.declare_function(name, Linkage::Import, &sig).unwrap()
+ match module.declare_function(name, Linkage::Import, &sig) {
+ Ok(func_id) => func_id,
+ Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+ "attempt to declare `{name}` as function, but it was already declared as static"
+ )),
+ Err(ModuleError::IncompatibleSignature(_, prev_sig, new_sig)) => tcx.sess.fatal(&format!(
+ "attempt to declare `{name}` with signature {new_sig:?}, \
+ but it was already declared with signature {prev_sig:?}"
+ )),
+ Err(err) => Err::<_, _>(err).unwrap(),
+ }
}
impl<'tcx> FunctionCx<'_, '_, 'tcx> {
}
let fn_abi = fx.fn_abi.take().unwrap();
+
+ // FIXME implement variadics in cranelift
+ if fn_abi.c_variadic {
+ fx.tcx.sess.span_fatal(
+ fx.mir.span,
+ "Defining variadic functions is not yet supported by Cranelift",
+ );
+ }
+
let mut arg_abis_iter = fn_abi.args.iter();
let func_params = fx
RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
};
- let is_cold = instance
- .map(|inst| fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD))
- .unwrap_or(false);
+ let is_cold = if fn_sig.abi == Abi::RustCold {
+ true
+ } else {
+ instance
+ .map(|inst| {
+ fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD)
+ })
+ .unwrap_or(false)
+ };
if is_cold {
fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
if let Some(destination_block) = target {
let clif_ty = match (reg.kind, reg.size.bytes()) {
(RegKind::Integer, 1) => types::I8,
(RegKind::Integer, 2) => types::I16,
- (RegKind::Integer, 4) => types::I32,
- (RegKind::Integer, 8) => types::I64,
- (RegKind::Integer, 16) => types::I128,
+ (RegKind::Integer, 3..=4) => types::I32,
+ (RegKind::Integer, 5..=8) => types::I64,
+ (RegKind::Integer, 9..=16) => types::I128,
(RegKind::Float, 4) => types::F32,
(RegKind::Float, 8) => types::F64,
(RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
)
};
- if cast.prefix.iter().all(|x| x.is_none()) {
- // Simplify to a single unit when there is no prefix and size <= unit size
- if cast.rest.total <= cast.rest.unit.size {
- let clif_ty = match (cast.rest.unit.kind, cast.rest.unit.size.bytes()) {
- (RegKind::Integer, 1) => types::I8,
- (RegKind::Integer, 2) => types::I16,
- (RegKind::Integer, 3..=4) => types::I32,
- (RegKind::Integer, 5..=8) => types::I64,
- (RegKind::Integer, 9..=16) => types::I128,
- (RegKind::Float, 4) => types::F32,
- (RegKind::Float, 8) => types::F64,
- (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
- _ => unreachable!("{:?}", cast.rest.unit),
- };
- return smallvec![AbiParam::new(clif_ty)];
- }
- }
+ // Note: Unlike the LLVM equivalent of this code we don't have separate branches for when there
+ // is no prefix as a single unit, an array and a heterogeneous struct are not represented using
+ // different types in Cranelift IR. Instead a single array of primitive types is used.
// Create list of fields in the main structure
let mut args = cast
arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
is_owned: bool,
) -> SmallVec<[Value; 2]> {
- assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty);
+ assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty, 16);
match arg_abi.mode {
PassMode::Ignore => smallvec![],
PassMode::Direct(_) => smallvec![arg.load_scalar(fx)],
let mut entries = Vec::new();
- for (entry_name, entry) in self.entries {
+ for (mut entry_name, entry) in self.entries {
// FIXME only read the symbol table of the object files to avoid having to keep all
// object files in memory at once, or read them twice.
let data = match entry {
};
if !self.no_builtin_ranlib {
+ if symbol_table.contains_key(&entry_name) {
+ // The ar crate can't handle creating a symbol table in case of multiple archive
+ // members with the same name. Work around this by prepending a number until we
+ // get a unique name.
+ for i in 1.. {
+ let new_name = format!("{}_", i)
+ .into_bytes()
+ .into_iter()
+ .chain(entry_name.iter().copied())
+ .collect::<Vec<_>>();
+ if !symbol_table.contains_key(&new_name) {
+ entry_name = new_name;
+ break;
+ }
+ }
+ }
+
match object::File::parse(&*data) {
Ok(object) => {
symbol_table.insert(
any_members
}
- fn inject_dll_import_lib(
- &mut self,
+ fn sess(&self) -> &Session {
+ self.sess
+ }
+
+ fn create_dll_import_lib(
+ _sess: &Session,
_lib_name: &str,
_dll_imports: &[rustc_session::cstore::DllImport],
- _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
- ) {
- bug!("injecting dll imports is not supported");
+ _tmpdir: &Path,
+ ) -> PathBuf {
+ bug!("creating dll imports is not supported");
}
}
);
});
+ #[cfg(any())] // This is never true
+ let _clif_guard = {
+ use std::fmt::Write;
+
+ let func_clone = context.func.clone();
+ let clif_comments_clone = clif_comments.clone();
+ let mut clif = String::new();
+ for flag in module.isa().flags().iter() {
+ writeln!(clif, "set {}", flag).unwrap();
+ }
+ write!(clif, "target {}", module.isa().triple().architecture.to_string()).unwrap();
+ for isa_flag in module.isa().isa_flags().iter() {
+ write!(clif, " {}", isa_flag).unwrap();
+ }
+ writeln!(clif, "\n").unwrap();
+ crate::PrintOnPanic(move || {
+ let mut clif = clif.clone();
+ ::cranelift_codegen::write::decorate_function(
+ &mut &clif_comments_clone,
+ &mut clif,
+ &func_clone,
+ )
+ .unwrap();
+ clif
+ })
+ };
+
// Define function
tcx.sess.time("define function", || {
context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
- module.define_function(func_id, context).unwrap()
+ module.define_function(func_id, context).unwrap();
});
// Write optimized function to file for debugging
for elem in place.projection {
match elem {
PlaceElem::Deref => {
- if cplace.layout().ty.is_box() {
- cplace = cplace
- .place_field(fx, Field::new(0)) // Box<T> -> Unique<T>
- .place_field(fx, Field::new(0)) // Unique<T> -> NonNull<T>
- .place_field(fx, Field::new(0)) // NonNull<T> -> *mut T
- .place_deref(fx);
- } else {
- cplace = cplace.place_deref(fx);
- }
+ cplace = cplace.place_deref(fx);
}
PlaceElem::Field(field, _ty) => {
cplace = cplace.place_field(fx, field);
}
let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from);
- if to_ty == types::I128 {
- // FIXME(bytecodealliance/wasmtime#3963): select.i128 on fcmp eq miscompiles
- let (lsb, msb) = fx.bcx.ins().isplit(val);
- let zero = fx.bcx.ins().iconst(types::I64, 0);
- let lsb = fx.bcx.ins().select(is_not_nan, lsb, zero);
- let msb = fx.bcx.ins().select(is_not_nan, msb, zero);
- fx.bcx.ins().iconcat(lsb, msb)
- } else {
- let zero = fx.bcx.ins().iconst(to_ty, 0);
- fx.bcx.ins().select(is_not_nan, val, zero)
- }
+ let zero = fx.bcx.ins().iconst(to_ty, 0);
+ fx.bcx.ins().select(is_not_nan, val, zero)
} else if from_ty.is_float() && to_ty.is_float() {
// float -> float
match (from_ty, to_ty) {
let attrs = tcx.codegen_fn_attrs(def_id);
- let data_id = module
- .declare_data(
- &*symbol_name,
- linkage,
- is_mutable,
- attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
- )
- .unwrap();
+ let data_id = match module.declare_data(
+ &*symbol_name,
+ linkage,
+ is_mutable,
+ attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
+ ) {
+ Ok(data_id) => data_id,
+ Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+ "attempt to declare `{symbol_name}` as static, but it was already declared as function"
+ )),
+ Err(err) => Err::<_, _>(err).unwrap(),
+ };
if rlinkage.is_some() {
// Comment copied from https://github.com/rust-lang/rust/blob/45060c2a66dfd667f88bd8b94261b28a58d85bd5/src/librustc_codegen_llvm/consts.rs#L141
let data_id = match reloc_target_alloc {
GlobalAlloc::Function(instance) => {
assert_eq!(addend, 0);
- let func_id = crate::abi::import_function(tcx, module, instance);
+ let func_id =
+ crate::abi::import_function(tcx, module, instance.polymorphize(tcx));
let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
data_ctx.write_function_addr(offset.bytes() as u32, local_func_id);
continue;
) {
// FIXME add .eh_frame unwind info directives
- if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
- let true_ = fx.bcx.ins().iconst(types::I32, 1);
- fx.bcx.ins().trapnz(true_, TrapCode::User(1));
- return;
- } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
- && matches!(
- template[1],
- InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
- )
- && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
- && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
- && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
- && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
- && matches!(
- template[6],
- InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
- )
- {
- assert_eq!(operands.len(), 4);
- let (leaf, eax_place) = match operands[1] {
- InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
- assert_eq!(
- reg,
- InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax))
- );
- (
- crate::base::codegen_operand(fx, in_value).load_scalar(fx),
- crate::base::codegen_place(fx, out_place.unwrap()),
- )
- }
- _ => unreachable!(),
- };
- let ebx_place = match operands[0] {
- InlineAsmOperand::Out { reg, late: true, place } => {
- assert_eq!(
- reg,
- InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
- X86InlineAsmRegClass::reg
- ))
- );
- crate::base::codegen_place(fx, place.unwrap())
- }
- _ => unreachable!(),
- };
- let (sub_leaf, ecx_place) = match operands[2] {
- InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
- assert_eq!(
- reg,
- InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx))
- );
- (
- crate::base::codegen_operand(fx, in_value).load_scalar(fx),
- crate::base::codegen_place(fx, out_place.unwrap()),
- )
- }
- _ => unreachable!(),
- };
- let edx_place = match operands[3] {
- InlineAsmOperand::Out { reg, late: true, place } => {
- assert_eq!(
- reg,
- InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx))
- );
- crate::base::codegen_place(fx, place.unwrap())
- }
- _ => unreachable!(),
- };
-
- let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf);
-
- eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
- ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
- ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
- edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
- return;
- } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
- // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
- crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
- } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
- crate::trap::trap_unimplemented(fx, "Alloca is not supported");
+ if !template.is_empty() {
+ if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
+ let true_ = fx.bcx.ins().iconst(types::I32, 1);
+ fx.bcx.ins().trapnz(true_, TrapCode::User(1));
+ return;
+ } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
+ && matches!(
+ template[1],
+ InlineAsmTemplatePiece::Placeholder {
+ operand_idx: 0,
+ modifier: Some('r'),
+ span: _
+ }
+ )
+ && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
+ && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
+ && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
+ && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
+ && matches!(
+ template[6],
+ InlineAsmTemplatePiece::Placeholder {
+ operand_idx: 0,
+ modifier: Some('r'),
+ span: _
+ }
+ )
+ {
+ assert_eq!(operands.len(), 4);
+ let (leaf, eax_place) = match operands[1] {
+ InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+ assert_eq!(
+ reg,
+ InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax))
+ );
+ (
+ crate::base::codegen_operand(fx, in_value).load_scalar(fx),
+ crate::base::codegen_place(fx, out_place.unwrap()),
+ )
+ }
+ _ => unreachable!(),
+ };
+ let ebx_place = match operands[0] {
+ InlineAsmOperand::Out { reg, late: true, place } => {
+ assert_eq!(
+ reg,
+ InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
+ X86InlineAsmRegClass::reg
+ ))
+ );
+ crate::base::codegen_place(fx, place.unwrap())
+ }
+ _ => unreachable!(),
+ };
+ let (sub_leaf, ecx_place) = match operands[2] {
+ InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+ assert_eq!(
+ reg,
+ InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx))
+ );
+ (
+ crate::base::codegen_operand(fx, in_value).load_scalar(fx),
+ crate::base::codegen_place(fx, out_place.unwrap()),
+ )
+ }
+ _ => unreachable!(),
+ };
+ let edx_place = match operands[3] {
+ InlineAsmOperand::Out { reg, late: true, place } => {
+ assert_eq!(
+ reg,
+ InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx))
+ );
+ crate::base::codegen_place(fx, place.unwrap())
+ }
+ _ => unreachable!(),
+ };
+
+ let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf);
+
+ eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
+ ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
+ ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
+ edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
+ return;
+ } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
+ // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
+ crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
+ } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
+ crate::trap::trap_unimplemented(fx, "Alloca is not supported");
+ }
}
let mut inputs = Vec::new();
ret: CPlace<'tcx>,
target: Option<BasicBlock>,
) {
- intrinsic_match! {
- fx, intrinsic, args,
- _ => {
- fx.tcx.sess.warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));
- crate::trap::trap_unimplemented(fx, intrinsic);
- };
-
+ match intrinsic {
// Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
- "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd", (c a) {
+ "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
+ intrinsic_args!(fx, args => (a); intrinsic);
+
let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
let lane_ty = fx.clif_type(lane_ty).unwrap();
assert!(lane_count <= 32);
let mut res = fx.bcx.ins().iconst(types::I32, 0);
for lane in (0..lane_count).rev() {
- let a_lane = a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx);
+ let a_lane =
+ a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx);
// cast float to int
let a_lane = match lane_ty {
let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
ret.write_cvalue(fx, res);
- };
- "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd", (c x, c y, o kind) {
- let kind = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const");
- let flt_cc = match kind.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind)) {
+ }
+ "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
+ let (x, y, kind) = match args {
+ [x, y, kind] => (x, y, kind),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let x = codegen_operand(fx, x);
+ let y = codegen_operand(fx, y);
+ let kind = crate::constant::mir_operand_get_const_val(fx, kind)
+ .expect("llvm.x86.sse2.cmp.* kind not const");
+
+ let flt_cc = match kind
+ .try_to_bits(Size::from_bytes(1))
+ .unwrap_or_else(|| panic!("kind not scalar: {:?}", kind))
+ {
0 => FloatCC::Equal,
1 => FloatCC::LessThan,
2 => FloatCC::LessThanOrEqual,
- 7 => {
- unimplemented!("Compares corresponding elements in `a` and `b` to see if neither is `NaN`.");
- }
- 3 => {
- unimplemented!("Compares corresponding elements in `a` and `b` to see if either is `NaN`.");
- }
+ 7 => FloatCC::Ordered,
+ 3 => FloatCC::Unordered,
4 => FloatCC::NotEqual,
- 5 => {
- unimplemented!("not less than");
- }
- 6 => {
- unimplemented!("not less than or equal");
- }
+ 5 => FloatCC::UnorderedOrGreaterThanOrEqual,
+ 6 => FloatCC::UnorderedOrGreaterThan,
kind => unreachable!("kind {:?}", kind),
};
};
bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
});
- };
- "llvm.x86.sse2.psrli.d", (c a, o imm8) {
- let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
- simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
- match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
- imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
- _ => fx.bcx.ins().iconst(types::I32, 0),
- }
+ }
+ "llvm.x86.sse2.psrli.d" => {
+ let (a, imm8) = match args {
+ [a, imm8] => (a, imm8),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let a = codegen_operand(fx, a);
+ let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
+ .expect("llvm.x86.sse2.psrli.d imm8 not const");
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
+ .try_to_bits(Size::from_bytes(4))
+ .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
+ {
+ imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
+ _ => fx.bcx.ins().iconst(types::I32, 0),
});
- };
- "llvm.x86.sse2.pslli.d", (c a, o imm8) {
- let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
- simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
- match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
- imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
- _ => fx.bcx.ins().iconst(types::I32, 0),
- }
+ }
+ "llvm.x86.sse2.pslli.d" => {
+ let (a, imm8) = match args {
+ [a, imm8] => (a, imm8),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let a = codegen_operand(fx, a);
+ let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
+ .expect("llvm.x86.sse2.psrli.d imm8 not const");
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
+ .try_to_bits(Size::from_bytes(4))
+ .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
+ {
+ imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
+ _ => fx.bcx.ins().iconst(types::I32, 0),
});
- };
- "llvm.x86.sse2.storeu.dq", (v mem_addr, c a) {
+ }
+ "llvm.x86.sse2.storeu.dq" => {
+ intrinsic_args!(fx, args => (mem_addr, a); intrinsic);
+ let mem_addr = mem_addr.load_scalar(fx);
+
// FIXME correctly handle the unalignment
let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
dest.write_cvalue(fx, a);
- };
- "llvm.x86.addcarry.64", (v c_in, c a, c b) {
- llvm_add_sub(
- fx,
- BinOp::Add,
- ret,
- c_in,
- a,
- b
- );
- };
- "llvm.x86.subborrow.64", (v b_in, c a, c b) {
- llvm_add_sub(
- fx,
- BinOp::Sub,
- ret,
- b_in,
- a,
- b
- );
- };
+ }
+ "llvm.x86.addcarry.64" => {
+ intrinsic_args!(fx, args => (c_in, a, b); intrinsic);
+ let c_in = c_in.load_scalar(fx);
+
+ llvm_add_sub(fx, BinOp::Add, ret, c_in, a, b);
+ }
+ "llvm.x86.subborrow.64" => {
+ intrinsic_args!(fx, args => (b_in, a, b); intrinsic);
+ let b_in = b_in.load_scalar(fx);
+
+ llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b);
+ }
+ _ => {
+ fx.tcx
+ .sess
+ .warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));
+ crate::trap::trap_unimplemented(fx, intrinsic);
+ }
}
let dest = target.expect("all llvm intrinsics used by stdlib should return");
//! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, `extern "platform-intrinsic"`
//! and LLVM intrinsics that have symbol names starting with `llvm.`.
-macro_rules! intrinsic_pat {
- (_) => {
- _
- };
- ($name:ident) => {
- sym::$name
- };
- (kw.$name:ident) => {
- kw::$name
- };
- ($name:literal) => {
- $name
- };
-}
-
-macro_rules! intrinsic_arg {
- (o $fx:expr, $arg:ident) => {};
- (c $fx:expr, $arg:ident) => {
- let $arg = codegen_operand($fx, $arg);
- };
- (v $fx:expr, $arg:ident) => {
- let $arg = codegen_operand($fx, $arg).load_scalar($fx);
- };
-}
-
-macro_rules! intrinsic_match {
- ($fx:expr, $intrinsic:expr, $args:expr,
- _ => $unknown:block;
- $(
- $($($name:tt).*)|+ $(if $cond:expr)?, ($($a:ident $arg:ident),*) $content:block;
- )*) => {
- match $intrinsic {
- $(
- $(intrinsic_pat!($($name).*))|* $(if $cond)? => {
- if let [$($arg),*] = $args {
- $(intrinsic_arg!($a $fx, $arg);)*
- $content
- } else {
- bug!("wrong number of args for intrinsic {:?}", $intrinsic);
- }
- }
- )*
- _ => $unknown,
- }
+macro_rules! intrinsic_args {
+ ($fx:expr, $args:expr => ($($arg:tt),*); $intrinsic:expr) => {
+ #[allow(unused_parens)]
+ let ($($arg),*) = if let [$($arg),*] = $args {
+ ($(codegen_operand($fx, $arg)),*)
+ } else {
+ $crate::intrinsics::bug_on_incorrect_arg_count($intrinsic);
+ };
}
}
use crate::prelude::*;
use cranelift_codegen::ir::AtomicRmwOp;
+fn bug_on_incorrect_arg_count(intrinsic: impl std::fmt::Display) -> ! {
+ bug!("wrong number of args for intrinsic {}", intrinsic);
+}
+
fn report_atomic_type_validation_error<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
intrinsic: Symbol,
) {
let usize_layout = fx.layout_of(fx.tcx.types.usize);
- intrinsic_match! {
- fx, intrinsic, args,
- _ => {
- fx.tcx.sess.span_fatal(source_info.span, &format!("unsupported intrinsic {}", intrinsic));
- };
+ match intrinsic {
+ sym::assume => {
+ intrinsic_args!(fx, args => (_a); intrinsic);
+ }
+ sym::likely | sym::unlikely => {
+ intrinsic_args!(fx, args => (a); intrinsic);
- assume, (c _a) {};
- likely | unlikely, (c a) {
ret.write_cvalue(fx, a);
- };
- breakpoint, () {
+ }
+ sym::breakpoint => {
+ intrinsic_args!(fx, args => (); intrinsic);
+
fx.bcx.ins().debugtrap();
- };
- copy | copy_nonoverlapping, (v src, v dst, v count) {
+ }
+ sym::copy | sym::copy_nonoverlapping => {
+ intrinsic_args!(fx, args => (src, dst, count); intrinsic);
+ let src = src.load_scalar(fx);
+ let dst = dst.load_scalar(fx);
+ let count = count.load_scalar(fx);
+
let elem_ty = substs.type_at(0);
let elem_size: u64 = fx.layout_of(elem_ty).size.bytes();
assert_eq!(args.len(), 3);
- let byte_amount = if elem_size != 1 {
- fx.bcx.ins().imul_imm(count, elem_size as i64)
- } else {
- count
- };
+ let byte_amount =
+ if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
if intrinsic == sym::copy_nonoverlapping {
// FIXME emit_small_memcpy
// FIXME emit_small_memmove
fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount);
}
- };
- // NOTE: the volatile variants have src and dst swapped
- volatile_copy_memory | volatile_copy_nonoverlapping_memory, (v dst, v src, v count) {
+ }
+ sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => {
+ // NOTE: the volatile variants have src and dst swapped
+ intrinsic_args!(fx, args => (dst, src, count); intrinsic);
+ let dst = dst.load_scalar(fx);
+ let src = src.load_scalar(fx);
+ let count = count.load_scalar(fx);
+
let elem_ty = substs.type_at(0);
let elem_size: u64 = fx.layout_of(elem_ty).size.bytes();
assert_eq!(args.len(), 3);
- let byte_amount = if elem_size != 1 {
- fx.bcx.ins().imul_imm(count, elem_size as i64)
- } else {
- count
- };
+ let byte_amount =
+ if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
// FIXME make the copy actually volatile when using emit_small_mem{cpy,move}
if intrinsic == sym::volatile_copy_nonoverlapping_memory {
// FIXME emit_small_memmove
fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount);
}
- };
- size_of_val, (c ptr) {
+ }
+ sym::size_of_val => {
+ intrinsic_args!(fx, args => (ptr); intrinsic);
+
let layout = fx.layout_of(substs.type_at(0));
- let size = if layout.is_unsized() {
+ // Note: Can't use is_unsized here as truly unsized types need to take the fixed size
+ // branch
+ let size = if let Abi::ScalarPair(_, _) = ptr.layout().abi {
let (_ptr, info) = ptr.load_scalar_pair(fx);
let (size, _align) = crate::unsize::size_and_align_of_dst(fx, layout, info);
size
} else {
- fx
- .bcx
- .ins()
- .iconst(fx.pointer_type, layout.size.bytes() as i64)
+ fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64)
};
ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
- };
- min_align_of_val, (c ptr) {
+ }
+ sym::min_align_of_val => {
+ intrinsic_args!(fx, args => (ptr); intrinsic);
+
let layout = fx.layout_of(substs.type_at(0));
- let align = if layout.is_unsized() {
+ // Note: Can't use is_unsized here as truly unsized types need to take the fixed size
+ // branch
+ let align = if let Abi::ScalarPair(_, _) = ptr.layout().abi {
let (_ptr, info) = ptr.load_scalar_pair(fx);
let (_size, align) = crate::unsize::size_and_align_of_dst(fx, layout, info);
align
} else {
- fx
- .bcx
- .ins()
- .iconst(fx.pointer_type, layout.align.abi.bytes() as i64)
+ fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64)
};
ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
- };
+ }
+
+ sym::vtable_size => {
+ intrinsic_args!(fx, args => (vtable); intrinsic);
+ let vtable = vtable.load_scalar(fx);
- vtable_size, (v vtable) {
let size = crate::vtable::size_of_obj(fx, vtable);
ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
- };
+ }
+
+ sym::vtable_align => {
+ intrinsic_args!(fx, args => (vtable); intrinsic);
+ let vtable = vtable.load_scalar(fx);
- vtable_align, (v vtable) {
let align = crate::vtable::min_align_of_obj(fx, vtable);
ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
- };
+ }
+
+ sym::unchecked_add
+ | sym::unchecked_sub
+ | sym::unchecked_mul
+ | sym::unchecked_div
+ | sym::exact_div
+ | sym::unchecked_rem
+ | sym::unchecked_shl
+ | sym::unchecked_shr => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
- unchecked_add | unchecked_sub | unchecked_mul | unchecked_div | exact_div | unchecked_rem
- | unchecked_shl | unchecked_shr, (c x, c y) {
// FIXME trap on overflow
let bin_op = match intrinsic {
sym::unchecked_add => BinOp::Add,
};
let res = crate::num::codegen_int_binop(fx, bin_op, x, y);
ret.write_cvalue(fx, res);
- };
- add_with_overflow | sub_with_overflow | mul_with_overflow, (c x, c y) {
+ }
+ sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
assert_eq!(x.layout().ty, y.layout().ty);
let bin_op = match intrinsic {
sym::add_with_overflow => BinOp::Add,
_ => unreachable!(),
};
- let res = crate::num::codegen_checked_int_binop(
- fx,
- bin_op,
- x,
- y,
- );
+ let res = crate::num::codegen_checked_int_binop(fx, bin_op, x, y);
ret.write_cvalue(fx, res);
- };
- saturating_add | saturating_sub, (c lhs, c rhs) {
+ }
+ sym::saturating_add | sym::saturating_sub => {
+ intrinsic_args!(fx, args => (lhs, rhs); intrinsic);
+
assert_eq!(lhs.layout().ty, rhs.layout().ty);
let bin_op = match intrinsic {
sym::saturating_add => BinOp::Add,
let signed = type_sign(lhs.layout().ty);
- let checked_res = crate::num::codegen_checked_int_binop(
- fx,
- bin_op,
- lhs,
- rhs,
- );
+ let checked_res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs);
let (val, has_overflow) = checked_res.load_scalar_pair(fx);
let clif_ty = fx.clif_type(lhs.layout().ty).unwrap();
(sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val),
(sym::saturating_add, true) => {
let rhs = rhs.load_scalar(fx);
- let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
+ let rhs_ge_zero =
+ fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
fx.bcx.ins().select(has_overflow, sat_val, val)
}
(sym::saturating_sub, true) => {
let rhs = rhs.load_scalar(fx);
- let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
+ let rhs_ge_zero =
+ fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max);
fx.bcx.ins().select(has_overflow, sat_val, val)
}
let res = CValue::by_val(val, lhs.layout());
ret.write_cvalue(fx, res);
- };
- rotate_left, (c x, v y) {
+ }
+ sym::rotate_left => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+ let y = y.load_scalar(fx);
+
let layout = x.layout();
let x = x.load_scalar(fx);
let res = fx.bcx.ins().rotl(x, y);
ret.write_cvalue(fx, CValue::by_val(res, layout));
- };
- rotate_right, (c x, v y) {
+ }
+ sym::rotate_right => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+ let y = y.load_scalar(fx);
+
let layout = x.layout();
let x = x.load_scalar(fx);
let res = fx.bcx.ins().rotr(x, y);
ret.write_cvalue(fx, CValue::by_val(res, layout));
- };
+ }
// The only difference between offset and arith_offset is regarding UB. Because Cranelift
// doesn't have UB both are codegen'ed the same way
- offset | arith_offset, (c base, v offset) {
+ sym::offset | sym::arith_offset => {
+ intrinsic_args!(fx, args => (base, offset); intrinsic);
+ let offset = offset.load_scalar(fx);
+
let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty;
let pointee_size = fx.layout_of(pointee_ty).size.bytes();
let ptr_diff = if pointee_size != 1 {
let base_val = base.load_scalar(fx);
let res = fx.bcx.ins().iadd(base_val, ptr_diff);
ret.write_cvalue(fx, CValue::by_val(res, base.layout()));
- };
+ }
+
+ sym::transmute => {
+ intrinsic_args!(fx, args => (from); intrinsic);
- transmute, (c from) {
ret.write_cvalue_transmute(fx, from);
- };
- write_bytes | volatile_set_memory, (c dst, v val, v count) {
+ }
+ sym::write_bytes | sym::volatile_set_memory => {
+ intrinsic_args!(fx, args => (dst, val, count); intrinsic);
+ let val = val.load_scalar(fx);
+ let count = count.load_scalar(fx);
+
let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap().ty;
let pointee_size = fx.layout_of(pointee_ty).size.bytes();
let count = if pointee_size != 1 {
// FIXME make the memset actually volatile when switching to emit_small_memset
// FIXME use emit_small_memset
fx.bcx.call_memset(fx.target_config, dst_ptr, val, count);
- };
- ctlz | ctlz_nonzero, (c arg) {
+ }
+ sym::ctlz | sym::ctlz_nonzero => {
+ intrinsic_args!(fx, args => (arg); intrinsic);
let val = arg.load_scalar(fx);
+
// FIXME trap on `ctlz_nonzero` with zero arg.
let res = fx.bcx.ins().clz(val);
let res = CValue::by_val(res, arg.layout());
ret.write_cvalue(fx, res);
- };
- cttz | cttz_nonzero, (c arg) {
+ }
+ sym::cttz | sym::cttz_nonzero => {
+ intrinsic_args!(fx, args => (arg); intrinsic);
let val = arg.load_scalar(fx);
+
// FIXME trap on `cttz_nonzero` with zero arg.
let res = fx.bcx.ins().ctz(val);
let res = CValue::by_val(res, arg.layout());
ret.write_cvalue(fx, res);
- };
- ctpop, (c arg) {
+ }
+ sym::ctpop => {
+ intrinsic_args!(fx, args => (arg); intrinsic);
let val = arg.load_scalar(fx);
+
let res = fx.bcx.ins().popcnt(val);
let res = CValue::by_val(res, arg.layout());
ret.write_cvalue(fx, res);
- };
- bitreverse, (c arg) {
+ }
+ sym::bitreverse => {
+ intrinsic_args!(fx, args => (arg); intrinsic);
let val = arg.load_scalar(fx);
+
let res = fx.bcx.ins().bitrev(val);
let res = CValue::by_val(res, arg.layout());
ret.write_cvalue(fx, res);
- };
- bswap, (c arg) {
+ }
+ sym::bswap => {
// FIXME(CraneStation/cranelift#794) add bswap instruction to cranelift
fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
match bcx.func.dfg.value_type(v) {
ty => unreachable!("bswap {}", ty),
}
}
+ intrinsic_args!(fx, args => (arg); intrinsic);
let val = arg.load_scalar(fx);
+
let res = CValue::by_val(swap(&mut fx.bcx, val), arg.layout());
ret.write_cvalue(fx, res);
- };
- assert_inhabited | assert_zero_valid | assert_uninit_valid, () {
+ }
+ sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
+ intrinsic_args!(fx, args => (); intrinsic);
+
let layout = fx.layout_of(substs.type_at(0));
if layout.abi.is_uninhabited() {
with_no_trimmed_paths!({
with_no_trimmed_paths!({
crate::base::codegen_panic(
fx,
- &format!("attempted to zero-initialize type `{}`, which is invalid", layout.ty),
+ &format!(
+ "attempted to zero-initialize type `{}`, which is invalid",
+ layout.ty
+ ),
source_info,
);
});
with_no_trimmed_paths!({
crate::base::codegen_panic(
fx,
- &format!("attempted to leave type `{}` uninitialized, which is invalid", layout.ty),
+ &format!(
+ "attempted to leave type `{}` uninitialized, which is invalid",
+ layout.ty
+ ),
source_info,
)
});
return;
}
- };
+ }
+
+ sym::volatile_load | sym::unaligned_volatile_load => {
+ intrinsic_args!(fx, args => (ptr); intrinsic);
- volatile_load | unaligned_volatile_load, (c ptr) {
// Cranelift treats loads as volatile by default
// FIXME correctly handle unaligned_volatile_load
- let inner_layout =
- fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
+ let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout);
ret.write_cvalue(fx, val);
- };
- volatile_store | unaligned_volatile_store, (v ptr, c val) {
+ }
+ sym::volatile_store | sym::unaligned_volatile_store => {
+ intrinsic_args!(fx, args => (ptr, val); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
// Cranelift treats stores as volatile by default
// FIXME correctly handle unaligned_volatile_store
let dest = CPlace::for_ptr(Pointer::new(ptr), val.layout());
dest.write_cvalue(fx, val);
- };
+ }
+
+ sym::pref_align_of
+ | sym::needs_drop
+ | sym::type_id
+ | sym::type_name
+ | sym::variant_count => {
+ intrinsic_args!(fx, args => (); intrinsic);
- pref_align_of | needs_drop | type_id | type_name | variant_count, () {
let const_val =
fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap();
- let val = crate::constant::codegen_const_value(
- fx,
- const_val,
- ret.layout().ty,
- );
+ let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty);
ret.write_cvalue(fx, val);
- };
+ }
- ptr_offset_from | ptr_offset_from_unsigned, (v ptr, v base) {
+ sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
+ intrinsic_args!(fx, args => (ptr, base); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+ let base = base.load_scalar(fx);
let ty = substs.type_at(0);
let pointee_size: u64 = fx.layout_of(ty).size.bytes();
CValue::by_val(fx.bcx.ins().sdiv_imm(diff_bytes, pointee_size as i64), isize_layout)
};
ret.write_cvalue(fx, val);
- };
+ }
+
+ sym::ptr_guaranteed_eq => {
+ intrinsic_args!(fx, args => (a, b); intrinsic);
- ptr_guaranteed_eq, (c a, c b) {
let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b);
ret.write_cvalue(fx, val);
- };
+ }
+
+ sym::ptr_guaranteed_ne => {
+ intrinsic_args!(fx, args => (a, b); intrinsic);
- ptr_guaranteed_ne, (c a, c b) {
let val = crate::num::codegen_ptr_binop(fx, BinOp::Ne, a, b);
ret.write_cvalue(fx, val);
- };
+ }
+
+ sym::caller_location => {
+ intrinsic_args!(fx, args => (); intrinsic);
- caller_location, () {
let caller_location = fx.get_caller_location(source_info);
ret.write_cvalue(fx, caller_location);
- };
+ }
+
+ _ if intrinsic.as_str().starts_with("atomic_fence") => {
+ intrinsic_args!(fx, args => (); intrinsic);
- _ if intrinsic.as_str().starts_with("atomic_fence"), () {
fx.bcx.ins().fence();
- };
- _ if intrinsic.as_str().starts_with("atomic_singlethreadfence"), () {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_singlethreadfence") => {
+ intrinsic_args!(fx, args => (); intrinsic);
+
// FIXME use a compiler fence once Cranelift supports it
fx.bcx.ins().fence();
- };
- _ if intrinsic.as_str().starts_with("atomic_load"), (v ptr) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_load") => {
+ intrinsic_args!(fx, args => (ptr); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let ty = substs.type_at(0);
match ty.kind() {
ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
fx.bcx.ins().jump(ret_block, &[]);
return;
} else {
- fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported");
+ fx.tcx
+ .sess
+ .span_fatal(source_info.span, "128bit atomics not yet supported");
}
}
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let val = CValue::by_val(val, fx.layout_of(ty));
ret.write_cvalue(fx, val);
- };
- _ if intrinsic.as_str().starts_with("atomic_store"), (v ptr, c val) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_store") => {
+ intrinsic_args!(fx, args => (ptr, val); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let ty = substs.type_at(0);
match ty.kind() {
ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
fx.bcx.ins().jump(ret_block, &[]);
return;
} else {
- fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported");
+ fx.tcx
+ .sess
+ .span_fatal(source_info.span, "128bit atomics not yet supported");
}
}
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let val = val.load_scalar(fx);
fx.bcx.ins().atomic_store(MemFlags::trusted(), val, ptr);
- };
- _ if intrinsic.as_str().starts_with("atomic_xchg"), (v ptr, c new) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_xchg") => {
+ intrinsic_args!(fx, args => (ptr, new); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let layout = new.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
- };
- _ if intrinsic.as_str().starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_*
+ }
+ _ if intrinsic.as_str().starts_with("atomic_cxchg") => {
+ // both atomic_cxchg_* and atomic_cxchgweak_*
+ intrinsic_args!(fx, args => (ptr, test_old, new); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let layout = new.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let old = fx.bcx.ins().atomic_cas(MemFlags::trusted(), ptr, test_old, new);
let is_eq = fx.bcx.ins().icmp(IntCC::Equal, old, test_old);
- let ret_val = CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout());
+ let ret_val =
+ CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout());
ret.write_cvalue(fx, ret_val)
- };
+ }
+
+ _ if intrinsic.as_str().starts_with("atomic_xadd") => {
+ intrinsic_args!(fx, args => (ptr, amount); intrinsic);
+ let ptr = ptr.load_scalar(fx);
- _ if intrinsic.as_str().starts_with("atomic_xadd"), (v ptr, c amount) {
let layout = amount.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let amount = amount.load_scalar(fx);
- let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Add, ptr, amount);
+ let old =
+ fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Add, ptr, amount);
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
- };
- _ if intrinsic.as_str().starts_with("atomic_xsub"), (v ptr, c amount) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_xsub") => {
+ intrinsic_args!(fx, args => (ptr, amount); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let layout = amount.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let amount = amount.load_scalar(fx);
- let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Sub, ptr, amount);
+ let old =
+ fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Sub, ptr, amount);
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
- };
- _ if intrinsic.as_str().starts_with("atomic_and"), (v ptr, c src) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_and") => {
+ intrinsic_args!(fx, args => (ptr, src); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let layout = src.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
- };
- _ if intrinsic.as_str().starts_with("atomic_or"), (v ptr, c src) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_or") => {
+ intrinsic_args!(fx, args => (ptr, src); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let layout = src.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
- };
- _ if intrinsic.as_str().starts_with("atomic_xor"), (v ptr, c src) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_xor") => {
+ intrinsic_args!(fx, args => (ptr, src); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let layout = src.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
- };
- _ if intrinsic.as_str().starts_with("atomic_nand"), (v ptr, c src) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_nand") => {
+ intrinsic_args!(fx, args => (ptr, src); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let layout = src.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
- };
- _ if intrinsic.as_str().starts_with("atomic_max"), (v ptr, c src) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_max") => {
+ intrinsic_args!(fx, args => (ptr, src); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let layout = src.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
- };
- _ if intrinsic.as_str().starts_with("atomic_umax"), (v ptr, c src) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_umax") => {
+ intrinsic_args!(fx, args => (ptr, src); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let layout = src.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
- };
- _ if intrinsic.as_str().starts_with("atomic_min"), (v ptr, c src) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_min") => {
+ intrinsic_args!(fx, args => (ptr, src); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let layout = src.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
- };
- _ if intrinsic.as_str().starts_with("atomic_umin"), (v ptr, c src) {
+ }
+ _ if intrinsic.as_str().starts_with("atomic_umin") => {
+ intrinsic_args!(fx, args => (ptr, src); intrinsic);
+ let ptr = ptr.load_scalar(fx);
+
let layout = src.layout();
match layout.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
- };
+ }
+
+ sym::minnumf32 => {
+ intrinsic_args!(fx, args => (a, b); intrinsic);
+ let a = a.load_scalar(fx);
+ let b = b.load_scalar(fx);
- minnumf32, (v a, v b) {
let val = crate::num::codegen_float_min(fx, a, b);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
ret.write_cvalue(fx, val);
- };
- minnumf64, (v a, v b) {
+ }
+ sym::minnumf64 => {
+ intrinsic_args!(fx, args => (a, b); intrinsic);
+ let a = a.load_scalar(fx);
+ let b = b.load_scalar(fx);
+
let val = crate::num::codegen_float_min(fx, a, b);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
ret.write_cvalue(fx, val);
- };
- maxnumf32, (v a, v b) {
+ }
+ sym::maxnumf32 => {
+ intrinsic_args!(fx, args => (a, b); intrinsic);
+ let a = a.load_scalar(fx);
+ let b = b.load_scalar(fx);
+
let val = crate::num::codegen_float_max(fx, a, b);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
ret.write_cvalue(fx, val);
- };
- maxnumf64, (v a, v b) {
+ }
+ sym::maxnumf64 => {
+ intrinsic_args!(fx, args => (a, b); intrinsic);
+ let a = a.load_scalar(fx);
+ let b = b.load_scalar(fx);
+
let val = crate::num::codegen_float_max(fx, a, b);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
ret.write_cvalue(fx, val);
- };
+ }
+
+ kw::Try => {
+ intrinsic_args!(fx, args => (f, data, catch_fn); intrinsic);
+ let f = f.load_scalar(fx);
+ let data = data.load_scalar(fx);
+ let _catch_fn = catch_fn.load_scalar(fx);
- kw.Try, (v f, v data, v _catch_fn) {
// FIXME once unwinding is supported, change this to actually catch panics
let f_sig = fx.bcx.func.import_signature(Signature {
call_conv: fx.target_config.default_call_conv,
let layout = ret.layout();
let ret_val = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
ret.write_cvalue(fx, ret_val);
- };
+ }
- fadd_fast | fsub_fast | fmul_fast | fdiv_fast | frem_fast, (c x, c y) {
- let res = crate::num::codegen_float_binop(fx, match intrinsic {
- sym::fadd_fast => BinOp::Add,
- sym::fsub_fast => BinOp::Sub,
- sym::fmul_fast => BinOp::Mul,
- sym::fdiv_fast => BinOp::Div,
- sym::frem_fast => BinOp::Rem,
- _ => unreachable!(),
- }, x, y);
+ sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ let res = crate::num::codegen_float_binop(
+ fx,
+ match intrinsic {
+ sym::fadd_fast => BinOp::Add,
+ sym::fsub_fast => BinOp::Sub,
+ sym::fmul_fast => BinOp::Mul,
+ sym::fdiv_fast => BinOp::Div,
+ sym::frem_fast => BinOp::Rem,
+ _ => unreachable!(),
+ },
+ x,
+ y,
+ );
ret.write_cvalue(fx, res);
- };
- float_to_int_unchecked, (v f) {
+ }
+ sym::float_to_int_unchecked => {
+ intrinsic_args!(fx, args => (f); intrinsic);
+ let f = f.load_scalar(fx);
+
let res = crate::cast::clif_int_or_float_cast(
fx,
f,
type_sign(ret.layout().ty),
);
ret.write_cvalue(fx, CValue::by_val(res, ret.layout()));
- };
+ }
+
+ sym::raw_eq => {
+ intrinsic_args!(fx, args => (lhs_ref, rhs_ref); intrinsic);
+ let lhs_ref = lhs_ref.load_scalar(fx);
+ let rhs_ref = rhs_ref.load_scalar(fx);
- raw_eq, (v lhs_ref, v rhs_ref) {
let size = fx.layout_of(substs.type_at(0)).layout.size();
// FIXME add and use emit_small_memcmp
- let is_eq_value =
- if size == Size::ZERO {
- // No bytes means they're trivially equal
- fx.bcx.ins().iconst(types::I8, 1)
- } else if let Some(clty) = size.bits().try_into().ok().and_then(Type::int) {
- // Can't use `trusted` for these loads; they could be unaligned.
- let mut flags = MemFlags::new();
- flags.set_notrap();
- let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
- let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
- let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
- fx.bcx.ins().bint(types::I8, eq)
- } else {
- // Just call `memcmp` (like slices do in core) when the
- // size is too large or it's not a power-of-two.
- let signed_bytes = i64::try_from(size.bytes()).unwrap();
- let bytes_val = fx.bcx.ins().iconst(fx.pointer_type, signed_bytes);
- let params = vec![AbiParam::new(fx.pointer_type); 3];
- let returns = vec![AbiParam::new(types::I32)];
- let args = &[lhs_ref, rhs_ref, bytes_val];
- let cmp = fx.lib_call("memcmp", params, returns, args)[0];
- let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
- fx.bcx.ins().bint(types::I8, eq)
- };
+ let is_eq_value = if size == Size::ZERO {
+ // No bytes means they're trivially equal
+ fx.bcx.ins().iconst(types::I8, 1)
+ } else if let Some(clty) = size.bits().try_into().ok().and_then(Type::int) {
+ // Can't use `trusted` for these loads; they could be unaligned.
+ let mut flags = MemFlags::new();
+ flags.set_notrap();
+ let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
+ let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
+ let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
+ fx.bcx.ins().bint(types::I8, eq)
+ } else {
+ // Just call `memcmp` (like slices do in core) when the
+ // size is too large or it's not a power-of-two.
+ let signed_bytes = i64::try_from(size.bytes()).unwrap();
+ let bytes_val = fx.bcx.ins().iconst(fx.pointer_type, signed_bytes);
+ let params = vec![AbiParam::new(fx.pointer_type); 3];
+ let returns = vec![AbiParam::new(types::I32)];
+ let args = &[lhs_ref, rhs_ref, bytes_val];
+ let cmp = fx.lib_call("memcmp", params, returns, args)[0];
+ let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
+ fx.bcx.ins().bint(types::I8, eq)
+ };
ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
- };
+ }
+
+ sym::const_allocate => {
+ intrinsic_args!(fx, args => (_size, _align); intrinsic);
- const_allocate, (c _size, c _align) {
// returns a null pointer at runtime.
let null = fx.bcx.ins().iconst(fx.pointer_type, 0);
ret.write_cvalue(fx, CValue::by_val(null, ret.layout()));
- };
+ }
- const_deallocate, (c _ptr, c _size, c _align) {
+ sym::const_deallocate => {
+ intrinsic_args!(fx, args => (_ptr, _size, _align); intrinsic);
// nop at runtime.
- };
+ }
+
+ sym::black_box => {
+ intrinsic_args!(fx, args => (a); intrinsic);
- black_box, (c a) {
// FIXME implement black_box semantics
ret.write_cvalue(fx, a);
- };
+ }
+
+ // FIXME implement variadics in cranelift
+ sym::va_copy | sym::va_arg | sym::va_end => {
+ fx.tcx.sess.span_fatal(
+ source_info.span,
+ "Defining variadic functions is not yet supported by Cranelift",
+ );
+ }
+
+ _ => {
+ fx.tcx
+ .sess
+ .span_fatal(source_info.span, &format!("unsupported intrinsic {}", intrinsic));
+ }
}
let ret_block = fx.get_block(destination.unwrap());
ret: CPlace<'tcx>,
span: Span,
) {
- intrinsic_match! {
- fx, intrinsic, args,
- _ => {
- fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
- };
+ match intrinsic {
+ sym::simd_cast => {
+ intrinsic_args!(fx, args => (a); intrinsic);
- simd_cast, (c a) {
if !a.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
return;
clif_int_or_float_cast(fx, lane, from_signed, ret_lane_clif_ty, to_signed)
});
- };
+ }
+
+ sym::simd_eq | sym::simd_ne | sym::simd_lt | sym::simd_le | sym::simd_gt | sym::simd_ge => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
- simd_eq | simd_ne | simd_lt | simd_le | simd_gt | simd_ge, (c x, c y) {
if !x.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
return;
simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| {
let res_lane = match (lane_ty.kind(), intrinsic) {
(ty::Uint(_), sym::simd_eq) => fx.bcx.ins().icmp(IntCC::Equal, x_lane, y_lane),
- (ty::Uint(_), sym::simd_ne) => fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane),
+ (ty::Uint(_), sym::simd_ne) => {
+ fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane)
+ }
(ty::Uint(_), sym::simd_lt) => {
fx.bcx.ins().icmp(IntCC::UnsignedLessThan, x_lane, y_lane)
}
}
(ty::Int(_), sym::simd_eq) => fx.bcx.ins().icmp(IntCC::Equal, x_lane, y_lane),
- (ty::Int(_), sym::simd_ne) => fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane),
- (ty::Int(_), sym::simd_lt) => fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane),
+ (ty::Int(_), sym::simd_ne) => {
+ fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane)
+ }
+ (ty::Int(_), sym::simd_lt) => {
+ fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane)
+ }
(ty::Int(_), sym::simd_le) => {
fx.bcx.ins().icmp(IntCC::SignedLessThanOrEqual, x_lane, y_lane)
}
fx.bcx.ins().icmp(IntCC::SignedGreaterThanOrEqual, x_lane, y_lane)
}
- (ty::Float(_), sym::simd_eq) => fx.bcx.ins().fcmp(FloatCC::Equal, x_lane, y_lane),
- (ty::Float(_), sym::simd_ne) => fx.bcx.ins().fcmp(FloatCC::NotEqual, x_lane, y_lane),
- (ty::Float(_), sym::simd_lt) => fx.bcx.ins().fcmp(FloatCC::LessThan, x_lane, y_lane),
+ (ty::Float(_), sym::simd_eq) => {
+ fx.bcx.ins().fcmp(FloatCC::Equal, x_lane, y_lane)
+ }
+ (ty::Float(_), sym::simd_ne) => {
+ fx.bcx.ins().fcmp(FloatCC::NotEqual, x_lane, y_lane)
+ }
+ (ty::Float(_), sym::simd_lt) => {
+ fx.bcx.ins().fcmp(FloatCC::LessThan, x_lane, y_lane)
+ }
(ty::Float(_), sym::simd_le) => {
fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, x_lane, y_lane)
}
- (ty::Float(_), sym::simd_gt) => fx.bcx.ins().fcmp(FloatCC::GreaterThan, x_lane, y_lane),
+ (ty::Float(_), sym::simd_gt) => {
+ fx.bcx.ins().fcmp(FloatCC::GreaterThan, x_lane, y_lane)
+ }
(ty::Float(_), sym::simd_ge) => {
fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, x_lane, y_lane)
}
let res_lane = fx.bcx.ins().bint(ty, res_lane);
fx.bcx.ins().ineg(res_lane)
});
- };
+ }
// simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
- _ if intrinsic.as_str().starts_with("simd_shuffle"), (c x, c y, o idx) {
+ _ if intrinsic.as_str().starts_with("simd_shuffle") => {
+ let (x, y, idx) = match args {
+ [x, y, idx] => (x, y, idx),
+ _ => {
+ bug!("wrong number of args for intrinsic {intrinsic}");
+ }
+ };
+ let x = codegen_operand(fx, x);
+ let y = codegen_operand(fx, y);
+
if !x.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
return;
// version of this intrinsic.
let idx_ty = fx.monomorphize(idx.ty(fx.mir, fx.tcx));
match idx_ty.kind() {
- ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
- len.try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| {
+ ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => len
+ .try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all())
+ .unwrap_or_else(|| {
span_bug!(span, "could not evaluate shuffle index array length")
- }).try_into().unwrap()
- }
+ })
+ .try_into()
+ .unwrap(),
_ => {
fx.tcx.sess.span_err(
span,
let indexes = {
use rustc_middle::mir::interpret::*;
- let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const");
+ let idx_const = crate::constant::mir_operand_get_const_val(fx, idx)
+ .expect("simd_shuffle* idx not const");
let idx_bytes = match idx_const {
ConstValue::ByRef { alloc, offset } => {
- let size = Size::from_bytes(4 * ret_lane_count /* size_of([u32; ret_lane_count]) */);
+ let size = Size::from_bytes(
+ 4 * ret_lane_count, /* size_of([u32; ret_lane_count]) */
+ );
alloc.inner().get_bytes(fx, alloc_range(offset, size)).unwrap()
}
_ => unreachable!("{:?}", idx_const),
};
- (0..ret_lane_count).map(|i| {
- let i = usize::try_from(i).unwrap();
- let idx = rustc_middle::mir::interpret::read_target_uint(
- fx.tcx.data_layout.endian,
- &idx_bytes[4*i.. 4*i + 4],
- ).expect("read_target_uint");
- u16::try_from(idx).expect("try_from u32")
- }).collect::<Vec<u16>>()
+ (0..ret_lane_count)
+ .map(|i| {
+ let i = usize::try_from(i).unwrap();
+ let idx = rustc_middle::mir::interpret::read_target_uint(
+ fx.tcx.data_layout.endian,
+ &idx_bytes[4 * i..4 * i + 4],
+ )
+ .expect("read_target_uint");
+ u16::try_from(idx).expect("try_from u32")
+ })
+ .collect::<Vec<u16>>()
};
for &idx in &indexes {
let out_lane = ret.place_lane(fx, u64::try_from(out_idx).unwrap());
out_lane.write_cvalue(fx, in_lane);
}
- };
+ }
+
+ sym::simd_insert => {
+ let (base, idx, val) = match args {
+ [base, idx, val] => (base, idx, val),
+ _ => {
+ bug!("wrong number of args for intrinsic {intrinsic}");
+ }
+ };
+ let base = codegen_operand(fx, base);
+ let val = codegen_operand(fx, val);
- simd_insert, (c base, o idx, c val) {
// FIXME validate
- let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
+ let idx_const = if let Some(idx_const) =
+ crate::constant::mir_operand_get_const_val(fx, idx)
+ {
idx_const
} else {
- fx.tcx.sess.span_fatal(
- span,
- "Index argument for `simd_insert` is not a constant",
- );
+ fx.tcx.sess.span_fatal(span, "Index argument for `simd_insert` is not a constant");
};
- let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
+ let idx = idx_const
+ .try_to_bits(Size::from_bytes(4 /* u32*/))
+ .unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx);
if idx >= lane_count.into() {
- fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count));
+ fx.tcx.sess.span_fatal(
+ fx.mir.span,
+ &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count),
+ );
}
ret.write_cvalue(fx, base);
let ret_lane = ret.place_field(fx, mir::Field::new(idx.try_into().unwrap()));
ret_lane.write_cvalue(fx, val);
- };
+ }
+
+ sym::simd_extract => {
+ let (v, idx) = match args {
+ [v, idx] => (v, idx),
+ _ => {
+ bug!("wrong number of args for intrinsic {intrinsic}");
+ }
+ };
+ let v = codegen_operand(fx, v);
- simd_extract, (c v, o idx) {
if !v.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
return;
}
- let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
+ let idx_const = if let Some(idx_const) =
+ crate::constant::mir_operand_get_const_val(fx, idx)
+ {
idx_const
} else {
- fx.tcx.sess.span_warn(
- span,
- "Index argument for `simd_extract` is not a constant",
- );
+ fx.tcx.sess.span_warn(span, "Index argument for `simd_extract` is not a constant");
let res = crate::trap::trap_unimplemented_ret_value(
fx,
ret.layout(),
return;
};
- let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
+ let idx = idx_const
+ .try_to_bits(Size::from_bytes(4 /* u32*/))
+ .unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx);
if idx >= lane_count.into() {
- fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
+ fx.tcx.sess.span_fatal(
+ fx.mir.span,
+ &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count),
+ );
}
let ret_lane = v.value_lane(fx, idx.try_into().unwrap());
ret.write_cvalue(fx, ret_lane);
- };
+ }
+
+ sym::simd_neg => {
+ intrinsic_args!(fx, args => (a); intrinsic);
- simd_neg, (c a) {
if !a.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
return;
}
- simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| {
- match lane_ty.kind() {
+ simd_for_each_lane(
+ fx,
+ a,
+ ret,
+ &|fx, lane_ty, _ret_lane_ty, lane| match lane_ty.kind() {
ty::Int(_) => fx.bcx.ins().ineg(lane),
ty::Float(_) => fx.bcx.ins().fneg(lane),
_ => unreachable!(),
- }
- });
- };
-
- simd_add | simd_sub | simd_mul | simd_div | simd_rem
- | simd_shl | simd_shr | simd_and | simd_or | simd_xor, (c x, c y) {
- if !x.layout().ty.is_simd() {
- report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
- return;
- }
+ },
+ );
+ }
+
+ sym::simd_add
+ | sym::simd_sub
+ | sym::simd_mul
+ | sym::simd_div
+ | sym::simd_rem
+ | sym::simd_shl
+ | sym::simd_shr
+ | sym::simd_and
+ | sym::simd_or
+ | sym::simd_xor => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
// FIXME use vector instructions when possible
- simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| match (
- lane_ty.kind(),
- intrinsic,
- ) {
- (ty::Uint(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane),
- (ty::Uint(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane),
- (ty::Uint(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane),
- (ty::Uint(_), sym::simd_div) => fx.bcx.ins().udiv(x_lane, y_lane),
- (ty::Uint(_), sym::simd_rem) => fx.bcx.ins().urem(x_lane, y_lane),
-
- (ty::Int(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane),
- (ty::Int(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane),
- (ty::Int(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane),
- (ty::Int(_), sym::simd_div) => fx.bcx.ins().sdiv(x_lane, y_lane),
- (ty::Int(_), sym::simd_rem) => fx.bcx.ins().srem(x_lane, y_lane),
-
- (ty::Float(_), sym::simd_add) => fx.bcx.ins().fadd(x_lane, y_lane),
- (ty::Float(_), sym::simd_sub) => fx.bcx.ins().fsub(x_lane, y_lane),
- (ty::Float(_), sym::simd_mul) => fx.bcx.ins().fmul(x_lane, y_lane),
- (ty::Float(_), sym::simd_div) => fx.bcx.ins().fdiv(x_lane, y_lane),
- (ty::Float(FloatTy::F32), sym::simd_rem) => fx.lib_call(
- "fmodf",
- vec![AbiParam::new(types::F32), AbiParam::new(types::F32)],
- vec![AbiParam::new(types::F32)],
- &[x_lane, y_lane],
- )[0],
- (ty::Float(FloatTy::F64), sym::simd_rem) => fx.lib_call(
- "fmod",
- vec![AbiParam::new(types::F64), AbiParam::new(types::F64)],
- vec![AbiParam::new(types::F64)],
- &[x_lane, y_lane],
- )[0],
-
- (ty::Uint(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane),
- (ty::Uint(_), sym::simd_shr) => fx.bcx.ins().ushr(x_lane, y_lane),
- (ty::Uint(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane),
- (ty::Uint(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane),
- (ty::Uint(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane),
-
- (ty::Int(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane),
- (ty::Int(_), sym::simd_shr) => fx.bcx.ins().sshr(x_lane, y_lane),
- (ty::Int(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane),
- (ty::Int(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane),
- (ty::Int(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane),
-
- _ => unreachable!(),
+ simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| {
+ match (lane_ty.kind(), intrinsic) {
+ (ty::Uint(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane),
+ (ty::Uint(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane),
+ (ty::Uint(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane),
+ (ty::Uint(_), sym::simd_div) => fx.bcx.ins().udiv(x_lane, y_lane),
+ (ty::Uint(_), sym::simd_rem) => fx.bcx.ins().urem(x_lane, y_lane),
+
+ (ty::Int(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane),
+ (ty::Int(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane),
+ (ty::Int(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane),
+ (ty::Int(_), sym::simd_div) => fx.bcx.ins().sdiv(x_lane, y_lane),
+ (ty::Int(_), sym::simd_rem) => fx.bcx.ins().srem(x_lane, y_lane),
+
+ (ty::Float(_), sym::simd_add) => fx.bcx.ins().fadd(x_lane, y_lane),
+ (ty::Float(_), sym::simd_sub) => fx.bcx.ins().fsub(x_lane, y_lane),
+ (ty::Float(_), sym::simd_mul) => fx.bcx.ins().fmul(x_lane, y_lane),
+ (ty::Float(_), sym::simd_div) => fx.bcx.ins().fdiv(x_lane, y_lane),
+ (ty::Float(FloatTy::F32), sym::simd_rem) => fx.lib_call(
+ "fmodf",
+ vec![AbiParam::new(types::F32), AbiParam::new(types::F32)],
+ vec![AbiParam::new(types::F32)],
+ &[x_lane, y_lane],
+ )[0],
+ (ty::Float(FloatTy::F64), sym::simd_rem) => fx.lib_call(
+ "fmod",
+ vec![AbiParam::new(types::F64), AbiParam::new(types::F64)],
+ vec![AbiParam::new(types::F64)],
+ &[x_lane, y_lane],
+ )[0],
+
+ (ty::Uint(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane),
+ (ty::Uint(_), sym::simd_shr) => fx.bcx.ins().ushr(x_lane, y_lane),
+ (ty::Uint(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane),
+ (ty::Uint(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane),
+ (ty::Uint(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane),
+
+ (ty::Int(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane),
+ (ty::Int(_), sym::simd_shr) => fx.bcx.ins().sshr(x_lane, y_lane),
+ (ty::Int(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane),
+ (ty::Int(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane),
+ (ty::Int(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane),
+
+ _ => unreachable!(),
+ }
});
- };
+ }
+
+ sym::simd_fma => {
+ intrinsic_args!(fx, args => (a, b, c); intrinsic);
- simd_fma, (c a, c b, c c) {
if !a.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
return;
let c_lane = c.value_lane(fx, lane);
let res_lane = match lane_ty.kind() {
- ty::Float(FloatTy::F32) => fx.easy_call("fmaf", &[a_lane, b_lane, c_lane], lane_ty),
- ty::Float(FloatTy::F64) => fx.easy_call("fma", &[a_lane, b_lane, c_lane], lane_ty),
+ ty::Float(FloatTy::F32) => {
+ fx.easy_call("fmaf", &[a_lane, b_lane, c_lane], lane_ty)
+ }
+ ty::Float(FloatTy::F64) => {
+ fx.easy_call("fma", &[a_lane, b_lane, c_lane], lane_ty)
+ }
_ => unreachable!(),
};
ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
}
- };
+ }
+
+ sym::simd_fmin | sym::simd_fmax => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
- simd_fmin | simd_fmax, (c x, c y) {
if !x.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
return;
// FIXME use vector instructions when possible
simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| {
match lane_ty.kind() {
- ty::Float(_) => {},
+ ty::Float(_) => {}
_ => unreachable!("{:?}", lane_ty),
}
match intrinsic {
_ => unreachable!(),
}
});
- };
+ }
+
+ sym::simd_round => {
+ intrinsic_args!(fx, args => (a); intrinsic);
- simd_round, (c a) {
if !a.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
return;
}
- simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| {
- match lane_ty.kind() {
+ simd_for_each_lane(
+ fx,
+ a,
+ ret,
+ &|fx, lane_ty, _ret_lane_ty, lane| match lane_ty.kind() {
ty::Float(FloatTy::F32) => fx.lib_call(
"roundf",
vec![AbiParam::new(types::F32)],
&[lane],
)[0],
_ => unreachable!("{:?}", lane_ty),
- }
- });
- };
+ },
+ );
+ }
+
+ sym::simd_fabs | sym::simd_fsqrt | sym::simd_ceil | sym::simd_floor | sym::simd_trunc => {
+ intrinsic_args!(fx, args => (a); intrinsic);
- simd_fabs | simd_fsqrt | simd_ceil | simd_floor | simd_trunc, (c a) {
if !a.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
return;
simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| {
match lane_ty.kind() {
- ty::Float(_) => {},
+ ty::Float(_) => {}
_ => unreachable!("{:?}", lane_ty),
}
match intrinsic {
_ => unreachable!(),
}
});
- };
+ }
+
+ sym::simd_reduce_add_ordered | sym::simd_reduce_add_unordered => {
+ intrinsic_args!(fx, args => (v, acc); intrinsic);
+ let acc = acc.load_scalar(fx);
- simd_reduce_add_ordered | simd_reduce_add_unordered, (c v, v acc) {
// FIXME there must be no acc param for integer vectors
if !v.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
fx.bcx.ins().iadd(a, b)
}
});
- };
+ }
+
+ sym::simd_reduce_mul_ordered | sym::simd_reduce_mul_unordered => {
+ intrinsic_args!(fx, args => (v, acc); intrinsic);
+ let acc = acc.load_scalar(fx);
- simd_reduce_mul_ordered | simd_reduce_mul_unordered, (c v, v acc) {
// FIXME there must be no acc param for integer vectors
if !v.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
fx.bcx.ins().imul(a, b)
}
});
- };
+ }
+
+ sym::simd_reduce_all => {
+ intrinsic_args!(fx, args => (v); intrinsic);
- simd_reduce_all, (c v) {
if !v.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
return;
}
simd_reduce_bool(fx, v, ret, &|fx, a, b| fx.bcx.ins().band(a, b));
- };
+ }
+
+ sym::simd_reduce_any => {
+ intrinsic_args!(fx, args => (v); intrinsic);
- simd_reduce_any, (c v) {
if !v.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
return;
}
simd_reduce_bool(fx, v, ret, &|fx, a, b| fx.bcx.ins().bor(a, b));
- };
+ }
+
+ sym::simd_reduce_and => {
+ intrinsic_args!(fx, args => (v); intrinsic);
- simd_reduce_and, (c v) {
if !v.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
return;
}
simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().band(a, b));
- };
+ }
+
+ sym::simd_reduce_or => {
+ intrinsic_args!(fx, args => (v); intrinsic);
- simd_reduce_or, (c v) {
if !v.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
return;
}
simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().bor(a, b));
- };
+ }
+
+ sym::simd_reduce_xor => {
+ intrinsic_args!(fx, args => (v); intrinsic);
- simd_reduce_xor, (c v) {
if !v.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
return;
}
simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().bxor(a, b));
- };
+ }
+
+ sym::simd_reduce_min => {
+ intrinsic_args!(fx, args => (v); intrinsic);
- simd_reduce_min, (c v) {
if !v.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
return;
};
fx.bcx.ins().select(lt, a, b)
});
- };
+ }
+
+ sym::simd_reduce_max => {
+ intrinsic_args!(fx, args => (v); intrinsic);
- simd_reduce_max, (c v) {
if !v.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
return;
};
fx.bcx.ins().select(gt, a, b)
});
- };
+ }
+
+ sym::simd_select => {
+ intrinsic_args!(fx, args => (m, a, b); intrinsic);
- simd_select, (c m, c a, c b) {
if !m.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, m.layout().ty);
return;
let b_lane = b.value_lane(fx, lane).load_scalar(fx);
let m_lane = fx.bcx.ins().icmp_imm(IntCC::Equal, m_lane, 0);
- let res_lane = CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout);
+ let res_lane =
+ CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout);
ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
}
- };
+ }
// simd_saturating_*
// simd_bitmask
// simd_scatter
// simd_gather
+ _ => {
+ fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
+ }
}
}
let unwind_context =
UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
- let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None };
+ let debug_context = if debug_info && !tcx.sess.target.options.is_like_windows {
+ Some(DebugContext::new(tcx, isa))
+ } else {
+ None
+ };
CodegenCx {
tcx,
global_asm: String::new(),
flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
flags_builder.set("enable_verifier", enable_verifier).unwrap();
+ flags_builder.set("regalloc_checker", enable_verifier).unwrap();
let tls_model = match target_triple.binary_format {
BinaryFormat::Elf => "elf_gd",
tcx.mk_substs([GenericArg::from(main_ret_ty)].iter()),
)
.unwrap()
- .unwrap();
+ .unwrap()
+ .polymorphize(tcx);
let report_name = tcx.symbol_name(report).name;
let report_sig = get_function_sig(tcx, m.isa().triple(), report);
use crate::prelude::*;
-#[derive(Debug)]
+#[derive(Clone, Debug)]
pub(crate) struct CommentWriter {
enabled: bool,
global_comments: Vec<String>,
func: &cranelift_codegen::ir::Function,
mut clif_comments: &CommentWriter,
) {
+ // FIXME work around filename too long errors
write_ir_file(
tcx,
|| format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
layout: TyAndLayout<'tcx>,
info: Value,
) -> (Value, Value) {
- if !layout.is_unsized() {
- let size = fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64);
- let align = fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64);
- return (size, align);
- }
+ assert!(layout.is_unsized() || layout.abi == Abi::Uninhabited);
match layout.ty.kind() {
ty::Dynamic(..) => {
// load size/align from vtable
};
}
+ if layout.size.bytes() >= u64::from(u32::MAX - 16) {
+ fx.tcx
+ .sess
+ .fatal(&format!("values of type {} are too big to store on the stack", layout.ty));
+ }
+
let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
}
pub(crate) fn write_cvalue(self, fx: &mut FunctionCx<'_, '_, 'tcx>, from: CValue<'tcx>) {
- assert_assignable(fx, from.layout().ty, self.layout().ty);
+ assert_assignable(fx, from.layout().ty, self.layout().ty, 16);
self.write_cvalue_maybe_transmute(fx, from, "write_cvalue");
}
fx: &FunctionCx<'_, '_, 'tcx>,
from_ty: Ty<'tcx>,
to_ty: Ty<'tcx>,
+ limit: usize,
) {
+ if limit == 0 {
+ // assert_assignable exists solely to catch bugs in cg_clif. it isn't necessary for
+ // soundness. don't attempt to check deep types to avoid exponential behavior in certain
+ // cases.
+ return;
+ }
match (from_ty.kind(), to_ty.kind()) {
(ty::Ref(_, a, _), ty::Ref(_, b, _))
| (
ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }),
ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }),
) => {
- assert_assignable(fx, *a, *b);
+ assert_assignable(fx, *a, *b, limit - 1);
}
(ty::Ref(_, a, _), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }))
| (ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::Ref(_, b, _)) => {
- assert_assignable(fx, *a, *b);
+ assert_assignable(fx, *a, *b, limit - 1);
}
(ty::FnPtr(_), ty::FnPtr(_)) => {
let from_sig = fx.tcx.normalize_erasing_late_bound_regions(
}
// dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed
}
+ (&ty::Tuple(types_a), &ty::Tuple(types_b)) => {
+ let mut types_a = types_a.iter();
+ let mut types_b = types_b.iter();
+ loop {
+ match (types_a.next(), types_b.next()) {
+ (Some(a), Some(b)) => assert_assignable(fx, a, b, limit - 1),
+ (None, None) => return,
+ (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty),
+ }
+ }
+ }
(&ty::Adt(adt_def_a, substs_a), &ty::Adt(adt_def_b, substs_b))
if adt_def_a.did() == adt_def_b.did() =>
{
let mut types_b = substs_b.types();
loop {
match (types_a.next(), types_b.next()) {
- (Some(a), Some(b)) => assert_assignable(fx, a, b),
+ (Some(a), Some(b)) => assert_assignable(fx, a, b, limit - 1),
(None, None) => return,
(Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty),
}
}
}
- (ty::Array(a, _), ty::Array(b, _)) => assert_assignable(fx, *a, *b),
+ (ty::Array(a, _), ty::Array(b, _)) => assert_assignable(fx, *a, *b, limit - 1),
+ (&ty::Closure(def_id_a, substs_a), &ty::Closure(def_id_b, substs_b))
+ if def_id_a == def_id_b =>
+ {
+ let mut types_a = substs_a.types();
+ let mut types_b = substs_b.types();
+ loop {
+ match (types_a.next(), types_b.next()) {
+ (Some(a), Some(b)) => assert_assignable(fx, a, b, limit - 1),
+ (None, None) => return,
+ (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty),
+ }
+ }
+ }
+ (ty::Param(_), _) | (_, ty::Param(_)) if fx.tcx.sess.opts.unstable_opts.polymorphize => {
+ // No way to check if it is correct or not with polymorphization enabled
+ }
_ => {
assert_eq!(
- from_ty, to_ty,
+ from_ty,
+ to_ty,
"Can't write value with incompatible type {:?} to place with type {:?}\n\n{:#?}",
- from_ty, to_ty, fx,
+ from_ty.kind(),
+ to_ty.kind(),
+ fx,
);
}
}
use rustc_codegen_ssa::back::archive::ArchiveBuilder;
use rustc_session::Session;
-use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_session::cstore::DllImport;
struct ArchiveConfig<'a> {
any_members
}
- fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) {
+ fn sess(&self) -> &Session {
+ self.config.sess
+ }
+
+ fn create_dll_import_lib(
+ _sess: &Session,
+ _lib_name: &str,
+ _dll_imports: &[DllImport],
+ _tmpdir: &Path,
+ ) -> PathBuf {
unimplemented!();
}
}
use crate::attributes;
use crate::llvm::AttributePlace::Function;
-use crate::llvm::{self, Attribute, AttributeKind, AttributePlace};
+use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace};
use crate::llvm_util;
pub use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
attrs
}
+fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
+ llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
+}
+
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
/// attributes.
pub fn from_fn_attrs<'ll, 'tcx>(
// Need this for AArch64.
to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false"));
}
- if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR)
+ || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
+ {
+ if llvm_util::get_version() >= (15, 0, 0) {
+ to_add.push(create_alloc_family_attr(cx.llcx));
+ // apply to argument place instead of function
+ let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
+ attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]);
+ to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0));
+ let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned;
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
+ flags |= AllocKindFlags::Uninitialized;
+ } else {
+ flags |= AllocKindFlags::Zeroed;
+ }
+ to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags));
+ }
// apply to return place instead of function (unlike all other attributes applied in this function)
let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
}
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::REALLOCATOR) {
+ if llvm_util::get_version() >= (15, 0, 0) {
+ to_add.push(create_alloc_family_attr(cx.llcx));
+ to_add.push(llvm::CreateAllocKindAttr(
+ cx.llcx,
+ AllocKindFlags::Realloc | AllocKindFlags::Aligned,
+ ));
+ // applies to argument place instead of function place
+ let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
+ attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
+ // apply to argument place instead of function
+ let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
+ attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]);
+ to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3));
+ }
+ let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
+ attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
+ }
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::DEALLOCATOR) {
+ if llvm_util::get_version() >= (15, 0, 0) {
+ to_add.push(create_alloc_family_attr(cx.llcx));
+ to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
+ // applies to argument place instead of function place
+ let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
+ attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
+ }
+ }
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry"));
}
use crate::llvm::archive_ro::{ArchiveRO, Child};
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
use rustc_codegen_ssa::back::archive::ArchiveBuilder;
-use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_session::cstore::{DllCallingConvention, DllImport};
use rustc_session::Session;
}
}
- fn inject_dll_import_lib(
- &mut self,
+ fn sess(&self) -> &Session {
+ self.sess
+ }
+
+ fn create_dll_import_lib(
+ sess: &Session,
lib_name: &str,
dll_imports: &[DllImport],
- tmpdir: &MaybeTempDir,
- ) {
+ tmpdir: &Path,
+ ) -> PathBuf {
let output_path = {
- let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf();
+ let mut output_path: PathBuf = tmpdir.to_path_buf();
output_path.push(format!("{}_imports", lib_name));
output_path.with_extension("lib")
};
- let target = &self.sess.target;
+ let target = &sess.target;
let mingw_gnu_toolchain = target.vendor == "pc"
&& target.os == "windows"
&& target.env == "gnu"
let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
.iter()
.map(|import: &DllImport| {
- if self.sess.target.arch == "x86" {
+ if sess.target.arch == "x86" {
(
LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
import.ordinal,
// that loaded but crashed with an AV upon calling one of the imported
// functions. Therefore, use binutils to create the import library instead,
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
- let def_file_path =
- tmpdir.as_ref().join(format!("{}_imports", lib_name)).with_extension("def");
+ let def_file_path = tmpdir.join(format!("{}_imports", lib_name)).with_extension("def");
let def_file_content = format!(
"EXPORTS\n{}",
match std::fs::write(&def_file_path, def_file_content) {
Ok(_) => {}
Err(e) => {
- self.sess.fatal(&format!("Error writing .DEF file: {}", e));
+ sess.fatal(&format!("Error writing .DEF file: {}", e));
}
};
- let dlltool = find_binutils_dlltool(self.sess);
+ let dlltool = find_binutils_dlltool(sess);
let result = std::process::Command::new(dlltool)
.args([
"-d",
match result {
Err(e) => {
- self.sess.fatal(&format!("Error calling dlltool: {}", e));
+ sess.fatal(&format!("Error calling dlltool: {}", e));
}
- Ok(output) if !output.status.success() => self.sess.fatal(&format!(
+ Ok(output) if !output.status.success() => sess.fatal(&format!(
"Dlltool could not create import library: {}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
output_path_z.as_ptr(),
ffi_exports.as_ptr(),
ffi_exports.len(),
- llvm_machine_type(&self.sess.target.arch) as u16,
- !self.sess.target.is_like_msvc,
+ llvm_machine_type(&sess.target.arch) as u16,
+ !sess.target.is_like_msvc,
)
};
if result == crate::llvm::LLVMRustResult::Failure {
- self.sess.fatal(&format!(
+ sess.fatal(&format!(
"Error creating import library for {}: {}",
lib_name,
llvm::last_error().unwrap_or("unknown LLVM error".to_string())
}
};
- self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
- self.sess.fatal(&format!(
- "failed to add native library {}: {}",
- output_path.display(),
- e
- ));
- });
+ output_path
}
}
OptimizationRemarkOther,
}
-impl OptimizationDiagnosticKind {
- pub fn describe(self) -> &'static str {
- match self {
- OptimizationRemark | OptimizationRemarkOther => "remark",
- OptimizationMissed => "missed",
- OptimizationAnalysis => "analysis",
- OptimizationAnalysisFPCommute => "floating-point",
- OptimizationAnalysisAliasing => "aliasing",
- OptimizationFailure => "failure",
- }
- }
-}
-
pub struct OptimizationDiagnostic<'ll> {
pub kind: OptimizationDiagnosticKind,
pub pass_name: String,
SanitizeMemTag = 34,
NoCfCheck = 35,
ShadowCallStack = 36,
+ AllocSize = 37,
+ AllocatedPointer = 38,
+ AllocAlign = 39,
}
/// LLVMIntPredicate
K_COFF,
}
-/// LLVMRustPassKind
-#[derive(Copy, Clone, PartialEq, Debug)]
-#[repr(C)]
-#[allow(dead_code)] // Variants constructed by C++.
-pub enum PassKind {
- Other,
- Function,
- Module,
-}
-
// LLVMRustThinLTOData
extern "C" {
pub type ThinLTOData;
pub type ThinLTOBuffer;
}
-// LLVMRustModuleNameCallback
-pub type ThinLTOModuleNameCallback =
- unsafe extern "C" fn(*mut c_void, *const c_char, *const c_char);
-
/// LLVMRustThinLTOModule
#[repr(C)]
pub struct ThinLTOModule {
}
#[repr(C)]
pub struct Builder<'a>(InvariantOpaque<'a>);
-extern "C" {
- pub type MemoryBuffer;
-}
#[repr(C)]
pub struct PassManager<'a>(InvariantOpaque<'a>);
extern "C" {
}
}
+use bitflags::bitflags;
+// These values **must** match with LLVMRustAllocKindFlags
+bitflags! {
+ #[repr(transparent)]
+ #[derive(Default)]
+ pub struct AllocKindFlags : u64 {
+ const Unknown = 0;
+ const Alloc = 1;
+ const Realloc = 1 << 1;
+ const Free = 1 << 2;
+ const Uninitialized = 1 << 3;
+ const Zeroed = 1 << 4;
+ const Aligned = 1 << 5;
+ }
+}
+
extern "C" {
pub type ModuleBuffer;
}
pub fn LLVMSetDataLayout(M: &Module, Triple: *const c_char);
/// See Module::setModuleInlineAsm.
- pub fn LLVMSetModuleInlineAsm2(M: &Module, Asm: *const c_char, AsmLen: size_t);
pub fn LLVMRustAppendModuleInlineAsm(M: &Module, Asm: *const c_char, AsmLen: size_t);
/// See llvm::LLVMTypeKind::getTypeID.
pub fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
pub fn LLVMSetInitializer<'a>(GlobalVar: &'a Value, ConstantVal: &'a Value);
pub fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool;
- pub fn LLVMSetThreadLocal(GlobalVar: &Value, IsThreadLocal: Bool);
pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
pub fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
pub fn LLVMRustCreateByValAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute;
pub fn LLVMRustCreateStructRetAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute;
pub fn LLVMRustCreateUWTableAttr(C: &Context, async_: bool) -> &Attribute;
+ pub fn LLVMRustCreateAllocSizeAttr(C: &Context, size_arg: u32) -> &Attribute;
+ pub fn LLVMRustCreateAllocKindAttr(C: &Context, size_arg: u64) -> &Attribute;
// Operations on functions
pub fn LLVMRustGetOrInsertFunction<'a>(
pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>;
- pub fn LLVMRustPassKind(Pass: &Pass) -> PassKind;
pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> Option<&'static mut Pass>;
pub fn LLVMRustCreateAddressSanitizerFunctionPass(Recover: bool) -> &'static mut Pass;
pub fn LLVMRustCreateModuleAddressSanitizerPass(Recover: bool) -> &'static mut Pass;
) -> LLVMRustResult;
pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char);
pub fn LLVMRustPrintPasses();
- pub fn LLVMRustGetInstructionCount(M: &Module) -> u32;
pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char);
pub fn LLVMRustAddAlwaysInlinePass(P: &PassManagerBuilder, AddLifetimes: bool);
pub fn LLVMRustRunRestrictionPass(M: &Module, syms: *const *const c_char, len: size_t);
pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock);
pub fn LLVMRustSetComdat<'a>(M: &'a Module, V: &'a Value, Name: *const c_char, NameLen: size_t);
- pub fn LLVMRustUnsetComdat(V: &Value);
pub fn LLVMRustSetModulePICLevel(M: &Module);
pub fn LLVMRustSetModulePIELevel(M: &Module);
pub fn LLVMRustSetModuleCodeModel(M: &Module, Model: CodeModel);
Module: &Module,
Target: &TargetMachine,
) -> bool;
- pub fn LLVMRustGetThinLTOModuleImports(
- Data: *const ThinLTOData,
- ModuleNameCallback: ThinLTOModuleNameCallback,
- CallbackPayload: *mut c_void,
- );
pub fn LLVMRustFreeThinLTOData(Data: &'static mut ThinLTOData);
pub fn LLVMRustParseBitcodeForLTO(
Context: &Context,
unsafe { LLVMRustCreateUWTableAttr(llcx, async_) }
}
+pub fn CreateAllocSizeAttr(llcx: &Context, size_arg: u32) -> &Attribute {
+ unsafe { LLVMRustCreateAllocSizeAttr(llcx, size_arg) }
+}
+
+pub fn CreateAllocKindAttr(llcx: &Context, kind_arg: AllocKindFlags) -> &Attribute {
+ unsafe { LLVMRustCreateAllocKindAttr(llcx, kind_arg.bits()) }
+}
+
#[derive(Copy, Clone)]
pub enum AttributePlace {
ReturnValue,
}
}
-pub fn UnsetComdat(val: &Value) {
- unsafe {
- LLVMRustUnsetComdat(val);
- }
-}
-
pub fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) {
unsafe {
LLVMSetUnnamedAddress(global, unnamed);
fn build(self) -> bool;
+ fn sess(&self) -> &Session;
+
+ /// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-import-library>.
+ /// and returns the path on disk to that import library.
+ /// This functions doesn't take `self` so that it can be called from
+ /// `linker_with_args`, which is specialized on `ArchiveBuilder` but
+ /// doesn't take or create an instance of that type.
+ fn create_dll_import_lib(
+ sess: &Session,
+ lib_name: &str,
+ dll_imports: &[DllImport],
+ tmpdir: &Path,
+ ) -> PathBuf;
+
+ /// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-import-library>
+ /// and adds it to the current compilation's set of archives.
fn inject_dll_import_lib(
&mut self,
lib_name: &str,
dll_imports: &[DllImport],
tmpdir: &MaybeTempDir,
- );
+ ) {
+ let output_path =
+ Self::create_dll_import_lib(self.sess(), lib_name, dll_imports, tmpdir.as_ref());
+
+ self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
+ self.sess().fatal(&format!(
+ "failed to add native library {}: {}",
+ output_path.display(),
+ e
+ ));
+ });
+ }
}
&out_filename,
codegen_results,
path.as_ref(),
- );
+ )?;
}
}
if sess.opts.json_artifact_notifications {
out_filename: &Path,
codegen_results: &CodegenResults,
tmpdir: &Path,
-) {
+) -> Result<(), ErrorGuaranteed> {
info!("preparing {:?} to {:?}", crate_type, out_filename);
let (linker_path, flavor) = linker_and_flavor(sess);
let mut cmd = linker_with_args::<B>(
tmpdir,
out_filename,
codegen_results,
- );
+ )?;
linker::disable_localization(&mut cmd);
(Strip::None, _) => {}
}
}
+
+ Ok(())
}
// Temporarily support both -Z strip and -C strip
tmpdir: &Path,
out_filename: &Path,
codegen_results: &CodegenResults,
-) -> Command {
+) -> Result<Command, ErrorGuaranteed> {
let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
let cmd = &mut *super::linker::get_linker(
sess,
add_upstream_native_libraries(cmd, sess, codegen_results);
}
+ // Link with the import library generated for any raw-dylib functions.
+ for (raw_dylib_name, raw_dylib_imports) in
+ collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
+ {
+ cmd.add_object(&B::create_dll_import_lib(
+ sess,
+ &raw_dylib_name,
+ &raw_dylib_imports,
+ tmpdir,
+ ));
+ }
+
// Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
// command line shorter, reset it to default here before adding more libraries.
cmd.reset_per_library_state();
// to it and remove the option.
add_post_link_args(cmd, sess, flavor);
- cmd.take_cmd()
+ Ok(cmd.take_cmd())
}
fn add_order_independent_options(
// sections to ensure we have all the data for PGO.
let keep_metadata =
crate_type == CrateType::Dylib || sess.opts.cg.profile_generate.enabled();
- cmd.gc_sections(keep_metadata);
+ if crate_type != CrateType::Executable || !sess.opts.unstable_opts.export_executable_symbols
+ {
+ cmd.gc_sections(keep_metadata);
+ } else {
+ cmd.no_gc_sections();
+ }
}
cmd.set_output_kind(link_output_kind, out_filename);
}
}
NativeLibKind::RawDylib => {
- // FIXME(#58713): Proper handling for raw dylibs.
- bug!("raw_dylib feature not yet implemented");
+ // Ignore RawDylib here, they are handled separately in linker_with_args().
}
}
}
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
// Symbol visibility in object files typically takes care of this.
- if crate_type == CrateType::Executable && self.sess.target.override_export_symbols.is_none()
- {
- return;
+ if crate_type == CrateType::Executable {
+ let should_export_executable_symbols =
+ self.sess.opts.unstable_opts.export_executable_symbols;
+ if self.sess.target.override_export_symbols.is_none()
+ && !should_export_executable_symbols
+ {
+ return;
+ }
}
// We manually create a list of exported symbols to ensure we don't expose any more.
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
// Symbol visibility takes care of this typically
if crate_type == CrateType::Executable {
- return;
+ let should_export_executable_symbols =
+ self.sess.opts.unstable_opts.export_executable_symbols;
+ if !should_export_executable_symbols {
+ return;
+ }
}
let path = tmpdir.join("lib.def");
LocalRef::Place(place) => place,
LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx),
LocalRef::Operand(..) => {
- if let Some(elem) = place_ref
- .projection
- .iter()
- .enumerate()
- .find(|elem| matches!(elem.1, mir::ProjectionElem::Deref))
- {
- base = elem.0 + 1;
+ if place_ref.has_deref() {
+ base = 1;
let cg_base = self.codegen_consume(
bx,
- mir::PlaceRef { projection: &place_ref.projection[..elem.0], ..place_ref },
+ mir::PlaceRef { projection: &place_ref.projection[..0], ..place_ref },
);
-
cg_base.deref(bx.cx())
} else {
bug!("using operand local {:?} as place", place_ref);
("bulk-memory", Some(sym::wasm_target_feature)),
("mutable-globals", Some(sym::wasm_target_feature)),
("reference-types", Some(sym::wasm_target_feature)),
+ ("sign-ext", Some(sym::wasm_target_feature)),
];
const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];
use rustc_hir::def_id::DefId;
use rustc_middle::mir::{
self,
- interpret::{ConstValue, GlobalId, InterpResult, Scalar},
+ interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar},
BinOp,
};
use rustc_middle::ty;
// We managed to find a valid allocation for one pointer, but not the other.
// That means they are definitely not pointing to the same allocation.
throw_ub_format!(
- "{} called on pointers into different allocations",
+ "`{}` called on pointers into different allocations",
intrinsic_name
);
}
// Found allocation for both. They must be into the same allocation.
if a_alloc_id != b_alloc_id {
throw_ub_format!(
- "{} called on pointers into different allocations",
+ "`{}` called on pointers into different allocations",
intrinsic_name
);
}
};
// Compute distance.
- let distance = {
- // The subtraction is always done in `isize` to enforce
- // the "no more than `isize::MAX` apart" requirement.
- let a_offset = ImmTy::from_uint(a_offset, isize_layout);
- let b_offset = ImmTy::from_uint(b_offset, isize_layout);
- let (val, overflowed, _ty) =
- self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
+ let dist = {
+ // Addresses are unsigned, so this is a `usize` computation. We have to do the
+ // overflow check separately anyway.
+ let (val, overflowed, _ty) = {
+ let a_offset = ImmTy::from_uint(a_offset, usize_layout);
+ let b_offset = ImmTy::from_uint(b_offset, usize_layout);
+ self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?
+ };
if overflowed {
- throw_ub_format!("pointers were too far apart for {}", intrinsic_name);
+ // a < b
+ if intrinsic_name == sym::ptr_offset_from_unsigned {
+ throw_ub_format!(
+ "`{}` called when first pointer has smaller offset than second: {} < {}",
+ intrinsic_name,
+ a_offset,
+ b_offset,
+ );
+ }
+ // The signed form of the intrinsic allows this. If we interpret the
+ // difference as isize, we'll get the proper signed difference. If that
+ // seems *positive*, they were more than isize::MAX apart.
+ let dist = val.to_machine_isize(self)?;
+ if dist >= 0 {
+ throw_ub_format!(
+ "`{}` called when first pointer is too far before second",
+ intrinsic_name
+ );
+ }
+ dist
+ } else {
+ // b >= a
+ let dist = val.to_machine_isize(self)?;
+ // If converting to isize produced a *negative* result, we had an overflow
+ // because they were more than isize::MAX apart.
+ if dist < 0 {
+ throw_ub_format!(
+ "`{}` called when first pointer is too far ahead of second",
+ intrinsic_name
+ );
+ }
+ dist
}
- val.to_machine_isize(self)?
};
// Check that the range between them is dereferenceable ("in-bounds or one past the
// end of the same allocation"). This is like the check in ptr_offset_inbounds.
- let min_ptr = if distance >= 0 { b } else { a };
+ let min_ptr = if dist >= 0 { b } else { a };
self.check_ptr_access_align(
min_ptr,
- Size::from_bytes(distance.unsigned_abs()),
+ Size::from_bytes(dist.unsigned_abs()),
Align::ONE,
CheckInAllocMsg::OffsetFromTest,
)?;
- if intrinsic_name == sym::ptr_offset_from_unsigned && distance < 0 {
- throw_ub_format!(
- "{} called when first pointer has smaller offset than second: {} < {}",
- intrinsic_name,
- a_offset,
- b_offset,
- );
- }
-
// Perform division by size to compute return value.
let ret_layout = if intrinsic_name == sym::ptr_offset_from_unsigned {
+ assert!(0 <= dist && dist <= self.machine_isize_max());
usize_layout
} else {
+ assert!(self.machine_isize_min() <= dist && dist <= self.machine_isize_max());
isize_layout
};
let pointee_layout = self.layout_of(substs.type_at(0))?;
// If ret_layout is unsigned, we checked that so is the distance, so we are good.
- let val = ImmTy::from_int(distance, ret_layout);
+ let val = ImmTy::from_int(dist, ret_layout);
let size = ImmTy::from_int(pointee_layout.size.bytes(), ret_layout);
self.exact_div(&val, &size, dest)?;
}
// Now determine the actual method to call. We can do that in two different ways and
// compare them to ensure everything fits.
- let ty::VtblEntry::Method(fn_inst) = self.get_vtable_entries(vptr)?[idx] else {
- span_bug!(self.cur_span(), "dyn call index points at something that is not a method")
+ let Some(ty::VtblEntry::Method(fn_inst)) = self.get_vtable_entries(vptr)?.get(idx).copied() else {
+ throw_ub_format!("`dyn` call trying to call something that is not a method")
};
if cfg!(debug_assertions) {
let tcx = *self.tcx;
use super::ConstCx;
use crate::errors::{
- MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrComparisonErr, RawPtrToIntErr,
- StaticAccessErr, TransientMutBorrowErr, TransientMutBorrowErrRaw,
+ MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr,
+ TransientMutBorrowErr, TransientMutBorrowErrRaw,
};
use crate::util::{call_kind, CallDesugaringKind, CallKind};
impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
fn build_error(
&self,
- ccx: &ConstCx<'_, 'tcx>,
+ _: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- ccx.tcx.sess.create_err(RawPtrComparisonErr { span })
+ span_bug!(span, "raw ptr comparison should already be caught in the trait system");
}
}
passes-link = attribute should be applied to an `extern` block with non-Rust ABI
.warn = {-passes-previously-accepted}
.label = not an `extern` block
+
+passes-link-name = attribute should be applied to a foreign function or static
+ .warn = {-passes-previously-accepted}
+ .label = not a foreign function or static
+ .help = try `#[link(name = "{$value}")]` instead
+
+passes-no-link = attribute should be applied to an `extern crate` item
+ .label = not an `extern crate` item
+
+passes-export-name = attribute should be applied to a free function, impl method or static
+ .label = not a free function, impl method or static
+
+passes-rustc-layout-scalar-valid-range-not-struct = attribute should be applied to a struct
+ .label = not a struct
+
+passes-rustc-layout-scalar-valid-range-arg = expected exactly one integer literal argument
+
+passes-rustc-legacy-const-generics-only = #[rustc_legacy_const_generics] functions must only have const generics
+ .label = non-const generic parameter
+
+passes-rustc-legacy-const-generics-index = #[rustc_legacy_const_generics] must have one index for each generic parameter
+ .label = generic parameters
+
+passes-rustc-legacy-const-generics-index-exceed = index exceeds number of arguments
+ .label = there {$arg_count ->
+ [one] is
+ *[other] are
+ } only {$arg_count} {$arg_count ->
+ [one] argument
+ *[other] arguments
+ }
+
+passes-rustc-legacy-const-generics-index-negative = arguments should be non-negative integers
+
+passes-rustc-dirty-clean = attribute requires -Z query-dep-graph to be enabled
+
+passes-link-section = attribute should be applied to a function or static
+ .warn = {-passes-previously-accepted}
+ .label = not a function or static
+
+passes-no-mangle-foreign = `#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
+ .warn = {-passes-previously-accepted}
+ .label = foreign {$foreign_item_kind}
+ .note = symbol names in extern blocks are not mangled
+ .suggestion = remove this attribute
+
+passes-no-mangle = attribute should be applied to a free function, impl method or static
+ .warn = {-passes-previously-accepted}
+ .label = not a free function, impl method or static
+
+passes-repr-ident = meta item in `repr` must be an identifier
+
+passes-repr-conflicting = conflicting representation hints
+
+passes-used-static = attribute must be applied to a `static` variable
+
+passes-used-compiler-linker = `used(compiler)` and `used(linker)` can't be used together
+
+passes-allow-internal-unstable = attribute should be applied to a macro
+ .label = not a macro
+
+passes-debug-visualizer-placement = attribute should be applied to a module
+
+passes-debug-visualizer-invalid = invalid argument
+ .note-1 = expected: `natvis_file = "..."`
+ .note-2 = OR
+ .note-3 = expected: `gdb_script_file = "..."`
+
+passes-rustc-allow-const-fn-unstable = attribute should be applied to `const fn`
+ .label = not a `const fn`
+
+passes-rustc-std-internal-symbol = attribute should be applied to functions or statics
+ .label = not a function or static
+
+passes-const-trait = attribute should be applied to a trait
+
+passes-stability-promotable = attribute cannot be applied to an expression
+
+passes-deprecated = attribute is ignored here
+
+passes-macro-use = `#[{$name}]` only has an effect on `extern crate` and modules
+
+passes-macro-export = `#[macro_export]` only has an effect on macro definitions
+
+passes-plugin-registrar = `#[plugin_registrar]` only has an effect on functions
+
+passes-unused-empty-lints-note = attribute `{$name}` with an empty list has no effect
+
+passes-unused-no-lints-note = attribute `{$name}` without any lints has no effect
+
+passes-unused-default-method-body-const-note =
+ `default_method_body_is_const` has been replaced with `#[const_trait]` on traits
+
+passes-unused = unused attribute
+ .suggestion = remove this attribute
+
+passes-non-exported-macro-invalid-attrs = attribute should be applied to function or closure
+ .label = not a function or closure
+
+passes-unused-duplicate = unused attribute
+ .suggestion = remove this attribute
+ .note = attribute also specified here
+ .warn = {-passes-previously-accepted}
+
+passes-unused-multiple = multiple `{$name}` attributes
+ .suggestion = remove this attribute
+ .note = attribute also specified here
rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+ rustc_attr!(rustc_reallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+ rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+ rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
gated!(
alloc_error_handler, Normal, template!(Word), WarnFollowing,
experimental!(alloc_error_handler)
}
/// Resolution for a lifetime appearing in a type.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum LifetimeRes {
/// Successfully linked the lifetime to a generic parameter.
Param {
span: Span,
hidden_ty: Ty<'tcx>,
hidden_region: ty::Region<'tcx>,
+ opaque_ty: ty::OpaqueTypeKey<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let opaque_ty = tcx.mk_opaque(opaque_ty.def_id.to_def_id(), opaque_ty.substs);
let mut err = struct_span_err!(
tcx.sess,
span,
E0700,
- "hidden type for `impl Trait` captures lifetime that does not appear in bounds",
+ "hidden type for `{opaque_ty}` captures lifetime that does not appear in bounds",
);
// Explain the region we are capturing.
exp_span, exp_found.expected, exp_found.found,
);
- if let ObligationCauseCode::CompareImplMethodObligation { .. } = cause.code() {
+ if let ObligationCauseCode::CompareImplItemObligation { .. } = cause.code() {
return;
}
GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
};
- if let Some(SubregionOrigin::CompareImplMethodObligation {
+ if let Some(SubregionOrigin::CompareImplItemObligation {
span,
impl_item_def_id,
trait_item_def_id,
#[derive(Debug)]
enum SubOrigin<'hir> {
GAT(&'hir hir::Generics<'hir>),
- Impl(&'hir hir::Generics<'hir>),
- Trait(&'hir hir::Generics<'hir>),
- Fn(&'hir hir::Generics<'hir>),
+ Impl,
+ Trait,
+ Fn,
Unknown,
}
let sub_origin = 'origin: {
kind: hir::ImplItemKind::TyAlias(..),
generics,
..
- }) => SubOrigin::GAT(generics),
- Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Fn(..),
- generics,
- ..
- }) => SubOrigin::Fn(generics),
- Node::TraitItem(hir::TraitItem {
+ })
+ | Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Type(..),
generics,
..
}) => SubOrigin::GAT(generics),
- Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(..),
- generics,
+ Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(..),
..
- }) => SubOrigin::Fn(generics),
- Node::Item(hir::Item {
- kind: hir::ItemKind::Trait(_, _, generics, _, _),
+ })
+ | Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(..),
..
- }) => SubOrigin::Trait(generics),
+ })
+ | Node::Item(hir::Item {
+ kind: hir::ItemKind::Fn(..), ..
+ }) => SubOrigin::Fn,
Node::Item(hir::Item {
- kind: hir::ItemKind::Impl(hir::Impl { generics, .. }),
+ kind: hir::ItemKind::Trait(..),
..
- }) => SubOrigin::Impl(generics),
+ }) => SubOrigin::Trait,
Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(_, generics, _),
- ..
- }) => SubOrigin::Fn(generics),
+ kind: hir::ItemKind::Impl(..), ..
+ }) => SubOrigin::Impl,
_ => continue,
};
}
use self::FailureCode::*;
use crate::traits::ObligationCauseCode::*;
match self.code() {
- CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
- CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"),
+ CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
+ Error0308("method not compatible with trait")
+ }
+ CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
+ Error0308("type not compatible with trait")
+ }
+ CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
+ Error0308("const not compatible with trait")
+ }
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => {
Error0308(match source {
hir::MatchSource::TryDesugar => "`?` operator has incompatible types",
fn as_requirement_str(&self) -> &'static str {
use crate::traits::ObligationCauseCode::*;
match self.code() {
- CompareImplMethodObligation { .. } => "method type is compatible with trait",
- CompareImplTypeObligation { .. } => "associated type is compatible with trait",
+ CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
+ "method type is compatible with trait"
+ }
+ CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
+ "associated type is compatible with trait"
+ }
+ CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
+ "const is compatible with trait"
+ }
ExprAssignable => "expression is assignable",
IfExpression { .. } => "`if` and `else` have incompatible types",
IfExpressionWithNoElse => "`if` missing an `else` returns `()`",
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::{SubregionOrigin, Subtype};
-use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
+use crate::infer::Subtype;
+use crate::traits::ObligationCauseCode::CompareImplItemObligation;
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::Res;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::print::RegionHighlightMode;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
use std::ops::ControlFlow;
let error = self.error.as_ref()?;
debug!("try_report_impl_not_conforming_to_trait {:?}", error);
if let RegionResolutionError::SubSupConflict(
- _, var_origin, sub_origin, _sub, sup_origin, _sup, _,
+ _,
+ var_origin,
+ sub_origin,
+ _sub,
+ sup_origin,
+ _sup,
+ _,
) = error.clone()
- && let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin)
- && let (
- sub_expected_found @ Some((sub_expected, sub_found)),
- sup_expected_found @ Some(_),
- CompareImplMethodObligation { trait_item_def_id, .. },
- ) = (sub_trace.values.ty(), sup_trace.values.ty(), sub_trace.cause.code())
+ && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
+ && let sub_expected_found @ Some((sub_expected, sub_found)) = sub_trace.values.ty()
+ && let sup_expected_found @ Some(_) = sup_trace.values.ty()
+ && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
&& sup_expected_found == sub_expected_found
{
- let guar = self.emit_err(
- var_origin.span(),
- sub_expected,
- sub_found,
- *trait_item_def_id,
- );
- return Some(guar);
- }
- if let RegionResolutionError::ConcreteFailure(origin, _, _)
- | RegionResolutionError::GenericBoundFailure(origin, _, _) = error.clone()
- && let SubregionOrigin::CompareImplTypeObligation {
- span,
- impl_item_def_id,
- trait_item_def_id,
- } = origin
- {
- let guar = self.emit_associated_type_err(
- span,
- self.infcx.tcx.item_name(impl_item_def_id.to_def_id()),
- impl_item_def_id,
- trait_item_def_id,
- );
+ let guar =
+ self.emit_err(var_origin.span(), sub_expected, sub_found, *trait_item_def_id);
return Some(guar);
}
None
}
err.emit()
}
-
- fn emit_associated_type_err(
- &self,
- span: Span,
- item_name: Symbol,
- impl_item_def_id: LocalDefId,
- trait_item_def_id: DefId,
- ) -> ErrorGuaranteed {
- let impl_sp = self.tcx().def_span(impl_item_def_id);
- let trait_sp = self.tcx().def_span(trait_item_def_id);
- let mut err = self
- .tcx()
- .sess
- .struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name));
- err.span_label(impl_sp, "found");
- err.span_label(trait_sp, "expected");
-
- err.emit()
- }
}
struct TypeParamSpanVisitor<'tcx> {
"...so that the declared lifetime parameter bounds are satisfied",
);
}
- infer::CompareImplMethodObligation { span, .. } => {
- label_or_note(
- span,
- "...so that the definition in impl matches the definition from the trait",
- );
- }
- infer::CompareImplTypeObligation { span, .. } => {
+ infer::CompareImplItemObligation { span, .. } => {
label_or_note(
span,
"...so that the definition in impl matches the definition from the trait",
);
err
}
- infer::CompareImplMethodObligation { span, impl_item_def_id, trait_item_def_id } => {
- self.report_extra_impl_obligation(
- span,
- impl_item_def_id,
- trait_item_def_id,
- &format!("`{}: {}`", sup, sub),
- )
- }
- infer::CompareImplTypeObligation { span, impl_item_def_id, trait_item_def_id } => self
+ infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
.report_extra_impl_obligation(
span,
impl_item_def_id,
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
use rustc_middle::traits::select;
-use rustc_middle::ty::abstract_const::AbstractConst;
+use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::relate::RelateResult;
/// Comparing the signature and requirements of an impl method against
/// the containing trait.
- CompareImplMethodObligation {
- span: Span,
- impl_item_def_id: LocalDefId,
- trait_item_def_id: DefId,
- },
-
- /// Comparing the signature and requirements of an impl associated type
- /// against the containing trait
- CompareImplTypeObligation { span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId },
+ CompareImplItemObligation { span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId },
/// Checking that the bounds of a trait's associated type hold for a given impl
CheckAssociatedTypeBounds {
#[instrument(skip(self), level = "debug")]
pub fn member_constraint(
&self,
- opaque_type_def_id: LocalDefId,
+ key: ty::OpaqueTypeKey<'tcx>,
definition_span: Span,
hidden_ty: Ty<'tcx>,
region: ty::Region<'tcx>,
in_regions: &Lrc<Vec<ty::Region<'tcx>>>,
) {
self.inner.borrow_mut().unwrap_region_constraints().member_constraint(
- opaque_type_def_id,
+ key,
definition_span,
hidden_ty,
region,
#[instrument(skip(self), level = "debug")]
pub fn const_eval_resolve(
&self,
- param_env: ty::ParamEnv<'tcx>,
+ mut param_env: ty::ParamEnv<'tcx>,
unevaluated: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
// variables
if substs.has_infer_types_or_consts() {
let ac = AbstractConst::new(self.tcx, unevaluated.shrink());
- if let Ok(None) = ac {
- substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did);
- } else {
- return Err(ErrorHandled::TooGeneric);
+ match ac {
+ Ok(None) => {
+ substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did);
+ param_env = self.tcx.param_env(unevaluated.def.did);
+ }
+ Ok(Some(ct)) => {
+ if ct.unify_failure_kind(self.tcx) == FailureKind::Concrete {
+ substs = replace_param_and_infer_substs_with_placeholder(self.tcx, substs);
+ } else {
+ return Err(ErrorHandled::TooGeneric);
+ }
+ }
+ Err(guar) => return Err(ErrorHandled::Reported(guar)),
}
}
ReborrowUpvar(a, _) => a,
DataBorrowed(_, a) => a,
ReferenceOutlivesReferent(_, a) => a,
- CompareImplMethodObligation { span, .. } => span,
- CompareImplTypeObligation { span, .. } => span,
+ CompareImplItemObligation { span, .. } => span,
CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
}
}
SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span)
}
- traits::ObligationCauseCode::CompareImplMethodObligation {
+ traits::ObligationCauseCode::CompareImplItemObligation {
impl_item_def_id,
trait_item_def_id,
- } => SubregionOrigin::CompareImplMethodObligation {
- span: cause.span,
- impl_item_def_id,
- trait_item_def_id,
- },
-
- traits::ObligationCauseCode::CompareImplTypeObligation {
- impl_item_def_id,
- trait_item_def_id,
- } => SubregionOrigin::CompareImplTypeObligation {
+ kind: _,
+ } => SubregionOrigin::CompareImplItemObligation {
span: cause.span,
impl_item_def_id,
trait_item_def_id,
)
}
}
+
+/// Replaces substs that reference param or infer variables with suitable
+/// placeholders. This function is meant to remove these param and infer
+/// substs when they're not actually needed to evaluate a constant.
+fn replace_param_and_infer_substs_with_placeholder<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ substs: SubstsRef<'tcx>,
+) -> SubstsRef<'tcx> {
+ tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| {
+ match arg.unpack() {
+ GenericArgKind::Type(_)
+ if arg.has_param_types_or_consts() || arg.has_infer_types_or_consts() =>
+ {
+ tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
+ universe: ty::UniverseIndex::ROOT,
+ name: ty::BoundVar::from_usize(idx),
+ }))
+ .into()
+ }
+ GenericArgKind::Const(ct)
+ if ct.has_infer_types_or_consts() || ct.has_param_types_or_consts() =>
+ {
+ let ty = ct.ty();
+ // If the type references param or infer, replace that too...
+ if ty.has_param_types_or_consts() || ty.has_infer_types_or_consts() {
+ bug!("const `{ct}`'s type should not reference params or types");
+ }
+ tcx.mk_const(ty::ConstS {
+ ty,
+ kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
+ universe: ty::UniverseIndex::ROOT,
+ name: ty::BoundConst { ty, var: ty::BoundVar::from_usize(idx) },
+ }),
+ })
+ .into()
+ }
+ _ => arg,
+ }
+ }))
+}
);
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
- op: |r| {
- self.member_constraint(
- opaque_type_key.def_id,
- span,
- concrete_ty,
- r,
- &choice_regions,
- )
- },
+ op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions),
});
}
}
#[instrument(skip(self), level = "trace")]
- pub fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin {
+ fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin {
let origin = match self.tcx.hir().expect_item(def_id).kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
ref itemkind => {
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify as ut;
-use rustc_hir::def_id::LocalDefId;
use rustc_index::vec::IndexVec;
use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
use rustc_middle::ty::ReStatic;
pub fn member_constraint(
&mut self,
- opaque_type_def_id: LocalDefId,
+ key: ty::OpaqueTypeKey<'tcx>,
definition_span: Span,
hidden_ty: Ty<'tcx>,
member_region: ty::Region<'tcx>,
}
self.data.member_constraints.push(MemberConstraint {
- opaque_type_def_id,
+ key,
definition_span,
hidden_ty,
member_region,
tracked!(debug_macros, true);
tracked!(dep_info_omit_d_target, true);
tracked!(drop_tracking, true);
+ tracked!(export_executable_symbols, true);
tracked!(dual_proc_macros, true);
tracked!(dwarf_version, Some(5));
tracked!(emit_thin_lto, false);
SanitizeMemTag = 34,
NoCfCheck = 35,
ShadowCallStack = 36,
+ AllocSize = 37,
+ AllocatedPointer = 38,
+ AllocAlign = 39,
};
typedef struct OpaqueRustString *RustStringRef;
timeTraceProfilerCleanup();
}
-enum class LLVMRustPassKind {
- Other,
- Function,
- Module,
-};
-
-static LLVMRustPassKind toRust(PassKind Kind) {
- switch (Kind) {
- case PT_Function:
- return LLVMRustPassKind::Function;
- case PT_Module:
- return LLVMRustPassKind::Module;
- default:
- return LLVMRustPassKind::Other;
- }
-}
-
extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) {
#if LLVM_VERSION_LT(15, 0)
StringRef SR(PassName);
#endif
}
-extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
- assert(RustPass);
- Pass *Pass = unwrap(RustPass);
- return toRust(Pass->getPassKind());
-}
-
extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) {
#if LLVM_VERSION_LT(15, 0)
assert(RustPass);
return true;
}
-extern "C" typedef void (*LLVMRustModuleNameCallback)(void*, // payload
- const char*, // importing module name
- const char*); // imported module name
-
-// Calls `module_name_callback` for each module import done by ThinLTO.
-// The callback is provided with regular null-terminated C strings.
-extern "C" void
-LLVMRustGetThinLTOModules(const LLVMRustThinLTOData *data,
- LLVMRustModuleNameCallback module_name_callback,
- void* callback_payload) {
- for (const auto& importing_module : data->ImportLists) {
- const std::string importing_module_id = importing_module.getKey().str();
- const auto& imports = importing_module.getValue();
- for (const auto& imported_module : imports) {
- const std::string imported_module_id = imported_module.getKey().str();
- module_name_callback(callback_payload,
- importing_module_id.c_str(),
- imported_module_id.c_str());
- }
- }
-}
-
// This struct and various functions are sort of a hack right now, but the
// problem is that we've got in-memory LLVM modules after we generate and
// optimize all codegen-units for one compilation in rustc. To be compatible
return Ret;
}
-extern "C" unsigned int LLVMRustGetInstructionCount(LLVMModuleRef M) {
- return unwrap(M)->getInstructionCount();
-}
-
extern "C" void LLVMRustSetLastError(const char *Err) {
free((void *)LastError);
LastError = strdup(Err);
return Attribute::SanitizeMemTag;
case ShadowCallStack:
return Attribute::ShadowCallStack;
+ case AllocSize:
+ return Attribute::AllocSize;
+#if LLVM_VERSION_GE(15, 0)
+ case AllocatedPointer:
+ return Attribute::AllocatedPointer;
+ case AllocAlign:
+ return Attribute::AllocAlign;
+#endif
}
report_fatal_error("bad AttributeKind");
}
#endif
}
+extern "C" LLVMAttributeRef LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) {
+ return wrap(Attribute::getWithAllocSizeArgs(*unwrap(C), ElementSizeArg, None));
+}
+
+#if LLVM_VERSION_GE(15, 0)
+
+// These values **must** match ffi::AllocKindFlags.
+// It _happens_ to match the LLVM values of llvm::AllocFnKind,
+// but that's happenstance and we do explicit conversions before
+// passing them to LLVM.
+enum class LLVMRustAllocKindFlags : uint64_t {
+ Unknown = 0,
+ Alloc = 1,
+ Realloc = 1 << 1,
+ Free = 1 << 2,
+ Uninitialized = 1 << 3,
+ Zeroed = 1 << 4,
+ Aligned = 1 << 5,
+};
+
+static LLVMRustAllocKindFlags operator&(LLVMRustAllocKindFlags A, LLVMRustAllocKindFlags B) {
+ return static_cast<LLVMRustAllocKindFlags>(static_cast<uint64_t>(A) &
+ static_cast<uint64_t>(B));
+}
+
+static bool isSet(LLVMRustAllocKindFlags F) { return F != LLVMRustAllocKindFlags::Unknown; }
+
+static llvm::AllocFnKind allocKindFromRust(LLVMRustAllocKindFlags F) {
+ llvm::AllocFnKind AFK = llvm::AllocFnKind::Unknown;
+ if (isSet(F & LLVMRustAllocKindFlags::Alloc)) {
+ AFK |= llvm::AllocFnKind::Alloc;
+ }
+ if (isSet(F & LLVMRustAllocKindFlags::Realloc)) {
+ AFK |= llvm::AllocFnKind::Realloc;
+ }
+ if (isSet(F & LLVMRustAllocKindFlags::Free)) {
+ AFK |= llvm::AllocFnKind::Free;
+ }
+ if (isSet(F & LLVMRustAllocKindFlags::Uninitialized)) {
+ AFK |= llvm::AllocFnKind::Uninitialized;
+ }
+ if (isSet(F & LLVMRustAllocKindFlags::Zeroed)) {
+ AFK |= llvm::AllocFnKind::Zeroed;
+ }
+ if (isSet(F & LLVMRustAllocKindFlags::Aligned)) {
+ AFK |= llvm::AllocFnKind::Aligned;
+ }
+ return AFK;
+}
+#endif
+
+extern "C" LLVMAttributeRef LLVMRustCreateAllocKindAttr(LLVMContextRef C, uint64_t AllocKindArg) {
+#if LLVM_VERSION_GE(15, 0)
+ return wrap(Attribute::get(*unwrap(C), Attribute::AllocKind,
+ static_cast<uint64_t>(allocKindFromRust(static_cast<LLVMRustAllocKindFlags>(AllocKindArg)))));
+#else
+ report_fatal_error(
+ "allockind attributes are new in LLVM 15 and should not be used on older LLVMs");
+#endif
+}
+
// Enable a fast-math flag
//
// https://llvm.org/docs/LangRef.html#fast-math-flags
}
}
-extern "C" void LLVMRustUnsetComdat(LLVMValueRef V) {
- GlobalObject *GV = unwrap<GlobalObject>(V);
- GV->setComdat(nullptr);
-}
-
enum class LLVMRustLinkage {
ExternalLinkage = 0,
AvailableExternallyLinkage = 1,
use std::iter::TrustedLen;
use std::mem;
use std::num::NonZeroUsize;
-use std::path::PathBuf;
+use std::path::Path;
use tracing::debug;
pub(super) use cstore_impl::provide;
/// Proc macro crates don't currently export spans, so this function does not have
/// to work for them.
fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] {
+ fn filter<'a>(sess: &Session, path: Option<&'a Path>) -> Option<&'a Path> {
+ path.filter(|_| {
+ // Only spend time on further checks if we have what to translate *to*.
+ sess.opts.real_rust_source_base_dir.is_some()
+ // Some tests need the translation to be always skipped.
+ && sess.opts.unstable_opts.translate_remapped_path_to_local_path
+ })
+ .filter(|virtual_dir| {
+ // Don't translate away `/rustc/$hash` if we're still remapping to it,
+ // since that means we're still building `std`/`rustc` that need it,
+ // and we don't want the real path to leak into codegen/debuginfo.
+ !sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir)
+ })
+ }
+
// Translate the virtual `/rustc/$hash` prefix back to a real directory
// that should hold actual sources, where possible.
//
// NOTE: if you update this, you might need to also update bootstrap's code for generating
// the `rust-src` component in `Src::run` in `src/bootstrap/dist.rs`.
let virtual_rust_source_base_dir = [
- option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from),
- sess.opts.unstable_opts.simulate_remapped_rust_src_base.clone(),
- ]
- .into_iter()
- .filter(|_| {
- // Only spend time on further checks if we have what to translate *to*.
- sess.opts.real_rust_source_base_dir.is_some()
- // Some tests need the translation to be always skipped.
- && sess.opts.unstable_opts.translate_remapped_path_to_local_path
- })
- .flatten()
- .filter(|virtual_dir| {
- // Don't translate away `/rustc/$hash` if we're still remapping to it,
- // since that means we're still building `std`/`rustc` that need it,
- // and we don't want the real path to leak into codegen/debuginfo.
- !sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir)
- })
- .collect::<Vec<_>>();
+ filter(sess, option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(Path::new)),
+ filter(sess, sess.opts.unstable_opts.simulate_remapped_rust_src_base.as_deref()),
+ ];
let try_to_translate_virtual_to_real = |name: &mut rustc_span::FileName| {
debug!(
name, virtual_rust_source_base_dir, sess.opts.real_rust_source_base_dir,
);
- for virtual_dir in &virtual_rust_source_base_dir {
+ for virtual_dir in virtual_rust_source_base_dir.iter().flatten() {
if let Some(real_dir) = &sess.opts.real_rust_source_base_dir {
if let rustc_span::FileName::Real(old_name) = name {
if let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } =
use std::collections::vec_deque::VecDeque;
let mut visible_parent_map: DefIdMap<DefId> = Default::default();
- // This is a secondary visible_parent_map, storing the DefId of parents that re-export
- // the child as `_`. Since we prefer parents that don't do this, merge this map at the
- // end, only if we're missing any keys from the former.
+ // This is a secondary visible_parent_map, storing the DefId of
+ // parents that re-export the child as `_` or module parents
+ // which are `#[doc(hidden)]`. Since we prefer paths that don't
+ // do this, merge this map at the end, only if we're missing
+ // keys from the former.
+ // This is a rudimentary check that does not catch all cases,
+ // just the easiest.
let mut fallback_map: DefIdMap<DefId> = Default::default();
// Issue 46112: We want the map to prefer the shortest
return;
}
+ if ty::util::is_doc_hidden(tcx, parent) {
+ fallback_map.insert(def_id, parent);
+ return;
+ }
+
match visible_parent_map.entry(def_id) {
Entry::Occupied(mut entry) => {
// If `child` is defined in crate `cnum`, ensure
}
}
- // Fill in any missing entries with the (less preferable) path ending in `::_`.
- // We still use this path in a diagnostic that suggests importing `::*`.
+ // Fill in any missing entries with the less preferable path.
+ // If this path re-exports the child as `_`, we still use this
+ // path in a diagnostic that suggests importing `::*`.
for (child, parent) in fallback_map {
visible_parent_map.entry(child).or_insert(parent);
}
pub mod unify_key;
use crate::ty::Region;
-use crate::ty::Ty;
+use crate::ty::{OpaqueTypeKey, Ty};
use rustc_data_structures::sync::Lrc;
-use rustc_hir::def_id::LocalDefId;
use rustc_span::Span;
/// Requires that `region` must be equal to one of the regions in `choice_regions`.
/// ```
#[derive(Debug, Clone, HashStable, TypeFoldable, TypeVisitable, Lift)]
pub struct MemberConstraint<'tcx> {
- /// The `DefId` of the opaque type causing this constraint: used for error reporting.
- pub opaque_type_def_id: LocalDefId,
+ /// The `DefId` and substs of the opaque type causing this constraint.
+ /// Used for error reporting.
+ pub key: OpaqueTypeKey<'tcx>,
/// The span where the hidden type was instantiated.
pub definition_span: Span,
/// the hot path.
const COLD = 1 << 0;
/// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this
- /// function is never null.
+ /// function is never null and the function has no side effects other than allocating.
const ALLOCATOR = 1 << 1;
/// An indicator that function will never unwind. Will become obsolete
/// once C-unwind is fully stabilized.
const NO_COVERAGE = 1 << 15;
/// `#[used(linker)]`: indicates that LLVM nor the linker can eliminate this function.
const USED_LINKER = 1 << 16;
+ /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory.
+ const DEALLOCATOR = 1 << 17;
+ /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory.
+ const REALLOCATOR = 1 << 18;
+ /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
+ const ALLOCATOR_ZEROED = 1 << 19;
}
}
}
let suggestion = suggestion_for_allocator_api(self, def_id, span, feature);
- EvalResult::Deny { feature, reason, issue, suggestion, is_soft }
+ EvalResult::Deny {
+ feature,
+ reason: reason.to_opt_reason(),
+ issue,
+ suggestion,
+ is_soft,
+ }
}
Some(_) => {
// Stable APIs are always ok to call and deprecated APIs are
self.projection.iter().any(|elem| elem.is_indirect())
}
+ /// If MirPhase >= Derefered and if projection contains Deref,
+ /// It's guaranteed to be in the first place
+ pub fn has_deref(&self) -> bool {
+ // To make sure this is not accidently used in wrong mir phase
+ debug_assert!(!self.projection[1..].contains(&PlaceElem::Deref));
+ self.projection.first() == Some(&PlaceElem::Deref)
+ }
+
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
/// a single deref of a local.
#[inline(always)]
}
}
+ /// If MirPhase >= Derefered and if projection contains Deref,
+ /// It's guaranteed to be in the first place
+ pub fn has_deref(&self) -> bool {
+ self.projection.first() == Some(&PlaceElem::Deref)
+ }
+
/// If this place represents a local variable like `_X` with no
/// projections, return `Some(_X)`.
#[inline]
},
/// Error derived when matching traits/impls; see ObligationCause for more details
- CompareImplConstObligation,
-
- /// Error derived when matching traits/impls; see ObligationCause for more details
- CompareImplMethodObligation {
- impl_item_def_id: LocalDefId,
- trait_item_def_id: DefId,
- },
-
- /// Error derived when matching traits/impls; see ObligationCause for more details
- CompareImplTypeObligation {
+ CompareImplItemObligation {
impl_item_def_id: LocalDefId,
trait_item_def_id: DefId,
+ kind: ty::AssocKind,
},
/// Checking that the bounds of a trait's associated type hold for a given impl
}
}
+impl std::fmt::Display for AssocKind {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ AssocKind::Fn => write!(f, "method"),
+ AssocKind::Const => write!(f, "associated const"),
+ AssocKind::Type => write!(f, "associated type"),
+ }
+ }
+}
+
/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
///
/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
}
/// Get the values inside the ValTree as a slice of bytes. This only works for
- /// constants with types &str and &[u8].
+ /// constants with types &str, &[u8], or [u8; _].
pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> {
match ty.kind() {
ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
- ty::Str => {
- let leafs = self
- .unwrap_branch()
- .into_iter()
- .map(|v| v.unwrap_leaf().try_to_u8().unwrap());
-
- return Some(tcx.arena.alloc_from_iter(leafs));
- }
- ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {
- let leafs = self
- .unwrap_branch()
- .into_iter()
- .map(|v| v.unwrap_leaf().try_to_u8().unwrap());
-
- return Some(tcx.arena.alloc_from_iter(leafs));
- }
- _ => {}
+ // `&str` can be interpreted as raw bytes
+ ty::Str => {}
+ // `&[u8]` can be interpreted as raw bytes
+ ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {}
+ // other `&_` can't be interpreted as raw bytes
+ _ => return None,
},
- _ => {}
+ // `[u8; N]` can be interpreted as raw bytes
+ ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {}
+ // Otherwise, type cannot be interpreted as raw bytes
+ _ => return None,
}
- None
+ Some(tcx.arena.alloc_from_iter(
+ self.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().try_to_u8().unwrap()),
+ ))
}
}
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
)
);
- let impl_comparison = matches!(
- cause_code,
- ObligationCauseCode::CompareImplMethodObligation { .. }
- | ObligationCauseCode::CompareImplTypeObligation { .. }
- | ObligationCauseCode::CompareImplConstObligation
- );
+ let impl_comparison =
+ matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
let assoc = self.associated_item(proj_ty.item_def_id);
if !callable_scope || impl_comparison {
// We do not want to suggest calling functions when the reason of the
pub fn is_const_if_const(self) -> bool {
self.constness == BoundConstness::ConstIfConst
}
+
+ pub fn is_constness_satisfied_by(self, constness: hir::Constness) -> bool {
+ match (self.constness, constness) {
+ (BoundConstness::NotConst, _)
+ | (BoundConstness::ConstIfConst, hir::Constness::Const) => true,
+ (BoundConstness::ConstIfConst, hir::Constness::NotConst) => false,
+ }
+ }
}
impl<'tcx> PolyTraitPredicate<'tcx> {
}
},
(ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => {
- let bytes = valtree.try_to_raw_bytes(self.tcx(), *t).unwrap_or_else(|| {
+ let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
bug!("expected to convert valtree to raw bytes for type {:?}", t)
});
p!("*");
ty::TraitPredicate<'tcx> {
p!(print(self.trait_ref.self_ty()), ": ");
- if let ty::BoundConstness::ConstIfConst = self.constness {
+ if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl {
p!("~const ");
}
p!(print(self.trait_ref.print_only_trait_path()))
// general `Region`.
crate::ty::BoundRegionKind,
crate::ty::AssocItem,
+ crate::ty::AssocKind,
crate::ty::Placeholder<crate::ty::BoundRegionKind>,
crate::ty::ClosureKind,
crate::ty::FreeRegion,
visitor.visit_predicate(*self)
}
+ #[inline]
fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
self.outer_exclusive_binder() > binder
}
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_serialize::{self, Decodable, Encodable};
-use rustc_span::DUMMY_SP;
use smallvec::SmallVec;
use core::intrinsics;
}
impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
+ #[inline]
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ #[cold]
+ #[inline(never)]
+ fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! {
+ bug!(
+ "Region parameter out of range when substituting in region {} (index={})",
+ data.name,
+ data.index
+ )
+ }
+
// Note: This routine only handles regions that are bound on
// type declarations and other outer declarations, not those
// bound in *fn types*. Region substitution of the bound
let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
match rk {
Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
- _ => {
- let msg = format!(
- "Region parameter out of range \
- when substituting in region {} (index={})",
- data.name, data.index
- );
- span_bug!(DUMMY_SP, "{}", msg);
- }
+ _ => region_param_out_of_range(data),
}
}
_ => r,
let opt_ty = self.substs.get(p.index as usize).map(|k| k.unpack());
let ty = match opt_ty {
Some(GenericArgKind::Type(ty)) => ty,
- Some(kind) => {
- span_bug!(
- DUMMY_SP,
- "expected type for `{:?}` ({:?}/{}) but found {:?} \
- when substituting, substs={:?}",
- p,
- source_ty,
- p.index,
- kind,
- self.substs,
- );
- }
- None => {
- span_bug!(
- DUMMY_SP,
- "type parameter `{:?}` ({:?}/{}) out of range \
- when substituting, substs={:?}",
- p,
- source_ty,
- p.index,
- self.substs,
- );
- }
+ Some(kind) => self.type_param_expected(p, source_ty, kind),
+ None => self.type_param_out_of_range(p, source_ty),
};
self.shift_vars_through_binders(ty)
}
+ #[cold]
+ #[inline(never)]
+ fn type_param_expected(&self, p: ty::ParamTy, ty: Ty<'tcx>, kind: GenericArgKind<'tcx>) -> ! {
+ bug!(
+ "expected type for `{:?}` ({:?}/{}) but found {:?} when substituting, substs={:?}",
+ p,
+ ty,
+ p.index,
+ kind,
+ self.substs,
+ )
+ }
+
+ #[cold]
+ #[inline(never)]
+ fn type_param_out_of_range(&self, p: ty::ParamTy, ty: Ty<'tcx>) -> ! {
+ bug!(
+ "type parameter `{:?}` ({:?}/{}) out of range when substituting, substs={:?}",
+ p,
+ ty,
+ p.index,
+ self.substs,
+ )
+ }
+
fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
// Look up the const in the substitutions. It really should be in there.
let opt_ct = self.substs.get(p.index as usize).map(|k| k.unpack());
let ct = match opt_ct {
Some(GenericArgKind::Const(ct)) => ct,
- Some(kind) => {
- span_bug!(
- DUMMY_SP,
- "expected const for `{:?}` ({:?}/{}) but found {:?} \
- when substituting substs={:?}",
- p,
- source_ct,
- p.index,
- kind,
- self.substs,
- );
- }
- None => {
- span_bug!(
- DUMMY_SP,
- "const parameter `{:?}` ({:?}/{}) out of range \
- when substituting substs={:?}",
- p,
- source_ct,
- p.index,
- self.substs,
- );
- }
+ Some(kind) => self.const_param_expected(p, source_ct, kind),
+ None => self.const_param_out_of_range(p, source_ct),
};
self.shift_vars_through_binders(ct)
}
+ #[cold]
+ #[inline(never)]
+ fn const_param_expected(
+ &self,
+ p: ty::ParamConst,
+ ct: ty::Const<'tcx>,
+ kind: GenericArgKind<'tcx>,
+ ) -> ! {
+ bug!(
+ "expected const for `{:?}` ({:?}/{}) but found {:?} when substituting substs={:?}",
+ p,
+ ct,
+ p.index,
+ kind,
+ self.substs,
+ )
+ }
+
+ #[cold]
+ #[inline(never)]
+ fn const_param_out_of_range(&self, p: ty::ParamConst, ct: ty::Const<'tcx>) -> ! {
+ bug!(
+ "const parameter `{:?}` ({:?}/{}) out of range when substituting substs={:?}",
+ p,
+ ct,
+ p.index,
+ self.substs,
+ )
+ }
+
/// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs
/// when we are substituting a type with escaping bound vars into a context where we have
/// passed through binders. That's quite a mouthful. Let's see an example:
let mut span: MultiSpan =
if spans.is_empty() { def_span.into() } else { spans.clone().into() };
- span.push_span_label(def_span, String::new());
+ span.push_span_label(def_span, "");
for pat in spans {
span.push_span_label(pat, "not covered");
}
/// (Concurrent accesses by other threads are no problem as these are anyway non-atomic
/// copies. Data races are UB.)
fn is_stable(place: PlaceRef<'_>) -> bool {
- place.projection.iter().all(|elem| {
- match elem {
- // Which place this evaluates to can change with any memory write,
- // so cannot assume this to be stable.
- ProjectionElem::Deref => false,
- // Array indices are interesting, but MIR building generates a *fresh*
- // temporary for every array access, so the index cannot be changed as
- // a side-effect.
- ProjectionElem::Index { .. } |
- // The rest is completely boring, they just offset by a constant.
- ProjectionElem::Field { .. } |
- ProjectionElem::ConstantIndex { .. } |
- ProjectionElem::Subslice { .. } |
- ProjectionElem::Downcast { .. } => true,
- }
- })
+ // Which place this evaluates to can change with any memory write,
+ // so cannot assume deref to be stable.
+ !place.has_deref()
}
/// Determine whether this type may contain a reference (or box), and thus needs retagging.
};
let place_base_raw = |place: &Place<'tcx>| {
// If this is a `Deref`, get the type of what we are deref'ing.
- let deref_base =
- place.projection.iter().rposition(|p| matches!(p, ProjectionElem::Deref));
- if let Some(deref_base) = deref_base {
- let base_proj = &place.projection[..deref_base];
- let ty = Place::ty_from(place.local, base_proj, &*local_decls, tcx).ty;
+ if place.has_deref() {
+ let ty = &local_decls[place.local].ty;
ty.is_unsafe_ptr()
} else {
// Not a deref, and thus not raw.
tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| {
// FIXME: when we make this a hard error, this should have its
// own error code.
- let message = if tcx.generics_of(def_id).own_requires_monomorphization() {
- "`#[derive]` can't be used on a `#[repr(packed)]` struct with \
- type or const parameters (error E0133)"
+ let extra = if tcx.generics_of(def_id).own_requires_monomorphization() {
+ "with type or const parameters"
} else {
- "`#[derive]` can't be used on a `#[repr(packed)]` struct that \
- does not derive Copy (error E0133)"
+ "that does not derive `Copy`"
};
+ let message = format!(
+ "`{}` can't be derived on this `#[repr(packed)]` struct {}",
+ tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")),
+ extra
+ );
lint.build(message).emit();
});
}
}
}
-struct ConstPropMachine<'mir, 'tcx> {
+pub struct ConstPropMachine<'mir, 'tcx> {
/// The virtual call stack.
stack: Vec<Frame<'mir, 'tcx>>,
/// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end.
- written_only_inside_own_block_locals: FxHashSet<Local>,
+ pub written_only_inside_own_block_locals: FxHashSet<Local>,
/// Locals that need to be cleared after every block terminates.
- only_propagate_inside_block_locals: BitSet<Local>,
- can_const_prop: IndexVec<Local, ConstPropMode>,
+ pub only_propagate_inside_block_locals: BitSet<Local>,
+ pub can_const_prop: IndexVec<Local, ConstPropMode>,
}
impl ConstPropMachine<'_, '_> {
- fn new(
+ pub fn new(
only_propagate_inside_block_locals: BitSet<Local>,
can_const_prop: IndexVec<Local, ConstPropMode>,
) -> Self {
/// The mode that `ConstProp` is allowed to run in for a given `Local`.
#[derive(Clone, Copy, Debug, PartialEq)]
-enum ConstPropMode {
+pub enum ConstPropMode {
/// The `Local` can be propagated into and reads of this `Local` can also be propagated.
FullConstProp,
/// The `Local` can only be propagated into and from its own block.
NoPropagation,
}
-struct CanConstProp {
+pub struct CanConstProp {
can_const_prop: IndexVec<Local, ConstPropMode>,
// False at the beginning. Once set, no more assignments are allowed to that local.
found_assignment: BitSet<Local>,
impl CanConstProp {
/// Returns true if `local` can be propagated
- fn check<'tcx>(
+ pub fn check<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
body: &Body<'tcx>,
//! Propagates constants for early reporting of statically known
//! assertion failures
-use std::cell::Cell;
-
-use rustc_ast::Mutability;
-use rustc_data_structures::fx::FxHashSet;
+use crate::const_prop::CanConstProp;
+use crate::const_prop::ConstPropMachine;
+use crate::const_prop::ConstPropMode;
+use crate::MirLint;
+use rustc_const_eval::const_eval::ConstEvalErr;
+use rustc_const_eval::interpret::{
+ self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar,
+ ScalarMaybeUninit, StackPopCleanup,
+};
use rustc_hir::def::DefKind;
use rustc_hir::HirId;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
-use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
+use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{
- AssertKind, BasicBlock, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, LocalKind,
- Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement,
- StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE,
+ AssertKind, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, Location, Operand, Place,
+ Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator,
+ TerminatorKind, UnOp, RETURN_PLACE,
};
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::subst::{InternalSubsts, Subst};
TypeVisitable,
};
use rustc_session::lint;
-use rustc_span::{def_id::DefId, Span};
+use rustc_span::Span;
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
-use rustc_target::spec::abi::Abi as CallAbi;
use rustc_trait_selection::traits;
-
-use crate::MirLint;
-use rustc_const_eval::const_eval::ConstEvalErr;
-use rustc_const_eval::interpret::{
- self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
- LocalState, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, ScalarMaybeUninit,
- StackPopCleanup, StackPopUnwind,
-};
+use std::cell::Cell;
/// The maximum number of bytes that we'll allocate space for a local or the return value.
/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
/// Severely regress performance.
const MAX_ALLOC_LIMIT: u64 = 1024;
-
-/// Macro for machine-specific `InterpError` without allocation.
-/// (These will never be shown to the user, but they help diagnose ICEs.)
-macro_rules! throw_machine_stop_str {
- ($($tt:tt)*) => {{
- // We make a new local type for it. The type itself does not carry any information,
- // but its vtable (for the `MachineStopType` trait) does.
- struct Zst;
- // Printing this type shows the desired string.
- impl std::fmt::Display for Zst {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, $($tt)*)
- }
- }
- impl rustc_middle::mir::interpret::MachineStopType for Zst {}
- throw_machine_stop!(Zst)
- }};
-}
-
pub struct ConstProp;
impl<'tcx> MirLint<'tcx> for ConstProp {
}
}
-struct ConstPropMachine<'mir, 'tcx> {
- /// The virtual call stack.
- stack: Vec<Frame<'mir, 'tcx>>,
- /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end.
- written_only_inside_own_block_locals: FxHashSet<Local>,
- /// Locals that need to be cleared after every block terminates.
- only_propagate_inside_block_locals: BitSet<Local>,
- can_const_prop: IndexVec<Local, ConstPropMode>,
-}
-
-impl ConstPropMachine<'_, '_> {
- fn new(
- only_propagate_inside_block_locals: BitSet<Local>,
- can_const_prop: IndexVec<Local, ConstPropMode>,
- ) -> Self {
- Self {
- stack: Vec::new(),
- written_only_inside_own_block_locals: Default::default(),
- only_propagate_inside_block_locals,
- can_const_prop,
- }
- }
-}
-
-impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> {
- compile_time_machine!(<'mir, 'tcx>);
- const PANIC_ON_ALLOC_FAIL: bool = true; // all allocations are small (see `MAX_ALLOC_LIMIT`)
-
- type MemoryKind = !;
-
- fn load_mir(
- _ecx: &InterpCx<'mir, 'tcx, Self>,
- _instance: ty::InstanceDef<'tcx>,
- ) -> InterpResult<'tcx, &'tcx Body<'tcx>> {
- throw_machine_stop_str!("calling functions isn't supported in ConstProp")
- }
-
- fn find_mir_or_eval_fn(
- _ecx: &mut InterpCx<'mir, 'tcx, Self>,
- _instance: ty::Instance<'tcx>,
- _abi: CallAbi,
- _args: &[OpTy<'tcx>],
- _destination: &PlaceTy<'tcx>,
- _target: Option<BasicBlock>,
- _unwind: StackPopUnwind,
- ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
- Ok(None)
- }
-
- fn call_intrinsic(
- _ecx: &mut InterpCx<'mir, 'tcx, Self>,
- _instance: ty::Instance<'tcx>,
- _args: &[OpTy<'tcx>],
- _destination: &PlaceTy<'tcx>,
- _target: Option<BasicBlock>,
- _unwind: StackPopUnwind,
- ) -> InterpResult<'tcx> {
- throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
- }
-
- fn assert_panic(
- _ecx: &mut InterpCx<'mir, 'tcx, Self>,
- _msg: &rustc_middle::mir::AssertMessage<'tcx>,
- _unwind: Option<rustc_middle::mir::BasicBlock>,
- ) -> InterpResult<'tcx> {
- bug!("panics terminators are not evaluated in ConstProp")
- }
-
- fn binary_ptr_op(
- _ecx: &InterpCx<'mir, 'tcx, Self>,
- _bin_op: BinOp,
- _left: &ImmTy<'tcx>,
- _right: &ImmTy<'tcx>,
- ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
- // We can't do this because aliasing of memory can differ between const eval and llvm
- throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
- }
-
- fn access_local<'a>(
- frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
- local: Local,
- ) -> InterpResult<'tcx, &'a interpret::Operand<Self::Provenance>> {
- let l = &frame.locals[local];
-
- if matches!(
- l.value,
- LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit))
- ) {
- // For us "uninit" means "we don't know its value, might be initiailized or not".
- // So stop here.
- throw_machine_stop_str!("tried to access a local with unknown value")
- }
-
- l.access()
- }
-
- fn access_local_mut<'a>(
- ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
- frame: usize,
- local: Local,
- ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::Provenance>> {
- if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation {
- throw_machine_stop_str!("tried to write to a local that is marked as not propagatable")
- }
- if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) {
- trace!(
- "mutating local {:?} which is restricted to its block. \
- Will remove it from const-prop after block is finished.",
- local
- );
- ecx.machine.written_only_inside_own_block_locals.insert(local);
- }
- ecx.machine.stack[frame].locals[local].access_mut()
- }
-
- fn before_access_global(
- _tcx: TyCtxt<'tcx>,
- _machine: &Self,
- _alloc_id: AllocId,
- alloc: ConstAllocation<'tcx, Self::Provenance, Self::AllocExtra>,
- _static_def_id: Option<DefId>,
- is_write: bool,
- ) -> InterpResult<'tcx> {
- if is_write {
- throw_machine_stop_str!("can't write to global");
- }
- // If the static allocation is mutable, then we can't const prop it as its content
- // might be different at runtime.
- if alloc.inner().mutability == Mutability::Mut {
- throw_machine_stop_str!("can't access mutable globals in ConstProp");
- }
-
- Ok(())
- }
-
- #[inline(always)]
- fn expose_ptr(
- _ecx: &mut InterpCx<'mir, 'tcx, Self>,
- _ptr: Pointer<AllocId>,
- ) -> InterpResult<'tcx> {
- throw_machine_stop_str!("exposing pointers isn't supported in ConstProp")
- }
-
- #[inline(always)]
- fn init_frame_extra(
- _ecx: &mut InterpCx<'mir, 'tcx, Self>,
- frame: Frame<'mir, 'tcx>,
- ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> {
- Ok(frame)
- }
-
- #[inline(always)]
- fn stack<'a>(
- ecx: &'a InterpCx<'mir, 'tcx, Self>,
- ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] {
- &ecx.machine.stack
- }
-
- #[inline(always)]
- fn stack_mut<'a>(
- ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
- ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
- &mut ecx.machine.stack
- }
-}
-
/// Finds optimization opportunities on the MIR.
struct ConstPropagator<'mir, 'tcx> {
ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
}
}
-/// The mode that `ConstProp` is allowed to run in for a given `Local`.
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum ConstPropMode {
- /// The `Local` can be propagated into and reads of this `Local` can also be propagated.
- FullConstProp,
- /// The `Local` can only be propagated into and from its own block.
- OnlyInsideOwnBlock,
- /// The `Local` can be propagated into but reads cannot be propagated.
- OnlyPropagateInto,
- /// The `Local` cannot be part of propagation at all. Any statement
- /// referencing it either for reading or writing will not get propagated.
- NoPropagation,
-}
-
-struct CanConstProp {
- can_const_prop: IndexVec<Local, ConstPropMode>,
- // False at the beginning. Once set, no more assignments are allowed to that local.
- found_assignment: BitSet<Local>,
- // Cache of locals' information
- local_kinds: IndexVec<Local, LocalKind>,
-}
-
-impl CanConstProp {
- /// Returns true if `local` can be propagated
- fn check<'tcx>(
- tcx: TyCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
- body: &Body<'tcx>,
- ) -> IndexVec<Local, ConstPropMode> {
- let mut cpv = CanConstProp {
- can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
- found_assignment: BitSet::new_empty(body.local_decls.len()),
- local_kinds: IndexVec::from_fn_n(
- |local| body.local_kind(local),
- body.local_decls.len(),
- ),
- };
- for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
- let ty = body.local_decls[local].ty;
- match tcx.layout_of(param_env.and(ty)) {
- Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
- // Either the layout fails to compute, then we can't use this local anyway
- // or the local is too large, then we don't want to.
- _ => {
- *val = ConstPropMode::NoPropagation;
- continue;
- }
- }
- // Cannot use args at all
- // Cannot use locals because if x < y { y - x } else { x - y } would
- // lint for x != y
- // FIXME(oli-obk): lint variables until they are used in a condition
- // FIXME(oli-obk): lint if return value is constant
- if cpv.local_kinds[local] == LocalKind::Arg {
- *val = ConstPropMode::OnlyPropagateInto;
- trace!(
- "local {:?} can't be const propagated because it's a function argument",
- local
- );
- } else if cpv.local_kinds[local] == LocalKind::Var {
- *val = ConstPropMode::OnlyInsideOwnBlock;
- trace!(
- "local {:?} will only be propagated inside its block, because it's a user variable",
- local
- );
- }
- }
- cpv.visit_body(&body);
- cpv.can_const_prop
- }
-}
-
-impl Visitor<'_> for CanConstProp {
- fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
- use rustc_middle::mir::visit::PlaceContext::*;
- match context {
- // Projections are fine, because `&mut foo.x` will be caught by
- // `MutatingUseContext::Borrow` elsewhere.
- MutatingUse(MutatingUseContext::Projection)
- // These are just stores, where the storing is not propagatable, but there may be later
- // mutations of the same local via `Store`
- | MutatingUse(MutatingUseContext::Call)
- | MutatingUse(MutatingUseContext::AsmOutput)
- | MutatingUse(MutatingUseContext::Deinit)
- // Actual store that can possibly even propagate a value
- | MutatingUse(MutatingUseContext::SetDiscriminant)
- | MutatingUse(MutatingUseContext::Store) => {
- if !self.found_assignment.insert(local) {
- match &mut self.can_const_prop[local] {
- // If the local can only get propagated in its own block, then we don't have
- // to worry about multiple assignments, as we'll nuke the const state at the
- // end of the block anyway, and inside the block we overwrite previous
- // states as applicable.
- ConstPropMode::OnlyInsideOwnBlock => {}
- ConstPropMode::NoPropagation => {}
- ConstPropMode::OnlyPropagateInto => {}
- other @ ConstPropMode::FullConstProp => {
- trace!(
- "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}",
- local, other,
- );
- *other = ConstPropMode::OnlyInsideOwnBlock;
- }
- }
- }
- }
- // Reading constants is allowed an arbitrary number of times
- NonMutatingUse(NonMutatingUseContext::Copy)
- | NonMutatingUse(NonMutatingUseContext::Move)
- | NonMutatingUse(NonMutatingUseContext::Inspect)
- | NonMutatingUse(NonMutatingUseContext::Projection)
- | NonUse(_) => {}
-
- // These could be propagated with a smarter analysis or just some careful thinking about
- // whether they'd be fine right now.
- MutatingUse(MutatingUseContext::Yield)
- | MutatingUse(MutatingUseContext::Drop)
- | MutatingUse(MutatingUseContext::Retag)
- // These can't ever be propagated under any scheme, as we can't reason about indirect
- // mutation.
- | NonMutatingUse(NonMutatingUseContext::SharedBorrow)
- | NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
- | NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
- | NonMutatingUse(NonMutatingUseContext::AddressOf)
- | MutatingUse(MutatingUseContext::Borrow)
- | MutatingUse(MutatingUseContext::AddressOf) => {
- trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
- self.can_const_prop[local] = ConstPropMode::NoPropagation;
- }
- }
- }
-}
-
impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
fn visit_body(&mut self, body: &Body<'tcx>) {
for (bb, data) in body.basic_blocks().iter_enumerated() {
/// with `0` executions.
///
/// If there are no live `Counter` `Coverage` statements remaining, we remove
-/// dead `Coverage` statements along with the dead blocks. Since at least one
+/// `Coverage` statements along with the dead blocks. Since at least one
/// counter per function is required by LLVM (and necessary, to add the
/// `function_hash` to the counter's call to the LLVM intrinsic
/// `instrprof.increment()`).
}
}
+ for block in &mut basic_blocks.raw[..first_dead_block] {
+ for statement in &mut block.statements {
+ let StatementKind::Coverage(_) = &statement.kind else { continue };
+ let instance = statement.source_info.scope.inlined_instance(source_scopes);
+ if !live.contains(&instance) {
+ statement.make_nop();
+ }
+ }
+ }
+
if live.is_empty() {
return;
}
use crate::errors;
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{fluent, pluralize, struct_span_err, Applicability, MultiSpan};
+use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan};
use rustc_expand::base::resolve_path;
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
_ => {
// FIXME: #[cold] was previously allowed on non-functions/statics and some crates
// used this, so only emit a warning.
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- let mut diag =
- lint.build("attribute should be applied to a foreign function or static");
- diag.warn(
- "this was previously accepted by the compiler but is \
- being phased out; it will become a hard error in \
- a future release!",
+ let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span);
+ if let Some(s) = attr.value_str() {
+ self.tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ errors::LinkName { span, attr_span, value: s.as_str() },
);
-
- // See issue #47725
- if let Target::ForeignMod = target {
- if let Some(value) = attr.value_str() {
- diag.span_help(
- attr.span,
- &format!(r#"try `#[link(name = "{value}")]` instead"#),
- );
- } else {
- diag.span_help(attr.span, r#"try `#[link(name = "...")]` instead"#);
- }
- }
-
- diag.span_label(span, "not a foreign function or static");
- diag.emit();
- });
+ } else {
+ self.tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ errors::LinkName { span, attr_span, value: "..." },
+ );
+ };
}
}
}
true
}
_ => {
- self.tcx
- .sess
- .struct_span_err(
- attr.span,
- "attribute should be applied to an `extern crate` item",
- )
- .span_label(span, "not an `extern crate` item")
- .emit();
+ self.tcx.sess.emit_err(errors::NoLink { attr_span: attr.span, span });
false
}
}
true
}
_ => {
- self.tcx
- .sess
- .struct_span_err(
- attr.span,
- "attribute should be applied to a free function, impl method or static",
- )
- .span_label(span, "not a free function, impl method or static")
- .emit();
+ self.tcx.sess.emit_err(errors::ExportName { attr_span: attr.span, span });
false
}
}
target: Target,
) -> bool {
if target != Target::Struct {
- self.tcx
- .sess
- .struct_span_err(attr.span, "attribute should be applied to a struct")
- .span_label(span, "not a struct")
- .emit();
+ self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeNotStruct {
+ attr_span: attr.span,
+ span,
+ });
return false;
}
if matches!(&list[..], &[NestedMetaItem::Literal(Lit { kind: LitKind::Int(..), .. })]) {
true
} else {
- self.tcx
- .sess
- .struct_span_err(attr.span, "expected exactly one integer literal argument")
- .emit();
+ self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span });
false
}
}
) -> bool {
let is_function = matches!(target, Target::Fn);
if !is_function {
- self.tcx
- .sess
- .struct_span_err(attr.span, "attribute should be applied to a function")
- .span_label(span, "not a function")
- .emit();
+ self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
+ attr_span: attr.span,
+ defn_span: span,
+ });
return false;
}
match param.kind {
hir::GenericParamKind::Const { .. } => {}
_ => {
- self.tcx
- .sess
- .struct_span_err(
- attr.span,
- "#[rustc_legacy_const_generics] functions must \
- only have const generics",
- )
- .span_label(param.span, "non-const generic parameter")
- .emit();
+ self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsOnly {
+ attr_span: attr.span,
+ param_span: param.span,
+ });
return false;
}
}
}
if list.len() != generics.params.len() {
- self.tcx
- .sess
- .struct_span_err(
- attr.span,
- "#[rustc_legacy_const_generics] must have one index for each generic parameter",
- )
- .span_label(generics.span, "generic parameters")
- .emit();
+ self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndex {
+ attr_span: attr.span,
+ generics_span: generics.span,
+ });
return false;
}
if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) {
if *val >= arg_count {
let span = meta.span();
- self.tcx
- .sess
- .struct_span_err(span, "index exceeds number of arguments")
- .span_label(
- span,
- format!(
- "there {} only {} argument{}",
- pluralize!("is", arg_count),
- arg_count,
- pluralize!(arg_count)
- ),
- )
- .emit();
+ self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexExceed {
+ span,
+ arg_count: arg_count as usize,
+ });
return false;
}
} else {
}
if !invalid_args.is_empty() {
- self.tcx
- .sess
- .struct_span_err(invalid_args, "arguments should be non-negative integers")
- .emit();
+ self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args });
false
} else {
true
fn check_applied_to_fn_or_method(&self, attr: &Attribute, span: Span, target: Target) -> bool {
let is_function = matches!(target, Target::Fn | Target::Method(..));
if !is_function {
- self.tcx
- .sess
- .struct_span_err(attr.span, "attribute should be applied to a function")
- .span_label(span, "not a function")
- .emit();
+ self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
+ attr_span: attr.span,
+ defn_span: span,
+ });
false
} else {
true
if self.tcx.sess.opts.unstable_opts.query_dep_graph {
true
} else {
- self.tcx
- .sess
- .struct_span_err(attr.span, "attribute requires -Z query-dep-graph to be enabled")
- .emit();
+ self.tcx.sess.emit_err(errors::RustcDirtyClean { span: attr.span });
false
}
}
_ => {
// FIXME: #[link_section] was previously allowed on non-functions/statics and some
// crates used this, so only emit a warning.
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build("attribute should be applied to a function or static")
- .warn(
- "this was previously accepted by the compiler but is \
- being phased out; it will become a hard error in \
- a future release!",
- )
- .span_label(span, "not a function or static")
- .emit();
- });
+ self.tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ errors::LinkSection { span },
+ );
}
}
}
Target::ForeignStatic => "static",
_ => unreachable!(),
};
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build(&format!(
- "`#[no_mangle]` has no effect on a foreign {foreign_item_kind}"
- ))
- .warn(
- "this was previously accepted by the compiler but is \
- being phased out; it will become a hard error in \
- a future release!",
- )
- .span_label(span, format!("foreign {foreign_item_kind}"))
- .note("symbol names in extern blocks are not mangled")
- .span_suggestion(
- attr.span,
- "remove this attribute",
- "",
- Applicability::MachineApplicable,
- )
- .emit();
- });
+ self.tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ errors::NoMangleForeign { span, attr_span: attr.span, foreign_item_kind },
+ );
}
_ => {
// FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
// crates used this, so only emit a warning.
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build(
- "attribute should be applied to a free function, impl method or static",
- )
- .warn(
- "this was previously accepted by the compiler but is \
- being phased out; it will become a hard error in \
- a future release!",
- )
- .span_label(span, "not a free function, impl method or static")
- .emit();
- });
+ self.tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ errors::NoMangle { span },
+ );
}
}
}
for hint in &hints {
if !hint.is_meta_item() {
- struct_span_err!(
- self.tcx.sess,
- hint.span(),
- E0565,
- "meta item in `repr` must be an identifier"
- )
- .emit();
+ self.tcx.sess.emit_err(errors::ReprIdent { span: hint.span() });
continue;
}
return false;
}))
{
- self.tcx.struct_span_lint_hir(
+ self.tcx.emit_spanned_lint(
CONFLICTING_REPR_HINTS,
hir_id,
hint_spans.collect::<Vec<Span>>(),
- |lint| {
- lint.build("conflicting representation hints")
- .code(rustc_errors::error_code!(E0566))
- .emit();
- },
+ errors::ReprConflicting,
);
}
}
let mut used_compiler_span = None;
for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) {
if target != Target::Static {
- self.tcx
- .sess
- .span_err(attr.span, "attribute must be applied to a `static` variable");
+ self.tcx.sess.emit_err(errors::UsedStatic { span: attr.span });
}
let inner = attr.meta_item_list();
match inner.as_deref() {
}
}
if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
- let spans = vec![linker_span, compiler_span];
self.tcx
.sess
- .struct_span_err(
- spans,
- "`used(compiler)` and `used(linker)` can't be used together",
- )
- .emit();
+ .emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] });
}
}
_ => {
self.tcx
.sess
- .struct_span_err(attr.span, "attribute should be applied to a macro")
- .span_label(span, "not a macro")
- .emit();
+ .emit_err(errors::AllowInternalUnstable { attr_span: attr.span, span });
false
}
}
match target {
Target::Mod => {}
_ => {
- self.tcx
- .sess
- .struct_span_err(attr.span, "attribute should be applied to a module")
- .emit();
+ self.tcx.sess.emit_err(errors::DebugVisualizerPlacement { span: attr.span });
return false;
}
}
let Some(hints) = attr.meta_item_list() else {
- self.emit_debugger_visualizer_err(attr.span);
+ self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
return false;
};
let hint = match hints.len() {
1 => &hints[0],
_ => {
- self.emit_debugger_visualizer_err(attr.span);
+ self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
return false;
}
};
let Some(meta_item) = hint.meta_item() else {
- self.emit_debugger_visualizer_err(attr.span);
+ self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
return false;
};
(sym::natvis_file, Some(value)) => value,
(sym::gdb_script_file, Some(value)) => value,
(_, _) => {
- self.emit_debugger_visualizer_err(meta_item.span);
+ self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: meta_item.span });
return false;
}
};
}
}
- fn emit_debugger_visualizer_err(&self, span: Span) {
- self.tcx
- .sess
- .struct_span_err(span, "invalid argument")
- .note(r#"expected: `natvis_file = "..."`"#)
- .note(r#"OR"#)
- .note(r#"expected: `gdb_script_file = "..."`"#)
- .emit();
- }
-
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
/// (Allows proc_macro functions)
fn check_rustc_allow_const_fn_unstable(
_ => {
self.tcx
.sess
- .struct_span_err(attr.span, "attribute should be applied to `const fn`")
- .span_label(span, "not a `const fn`")
- .emit();
+ .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span, span });
false
}
}
_ => {
self.tcx
.sess
- .struct_span_err(attr.span, "attribute should be applied functions or statics")
- .span_label(span, "not a function or static")
- .emit();
+ .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span, span });
false
}
}
match target {
Target::Trait => true,
_ => {
- self.tcx
- .sess
- .struct_span_err(attr.span, "attribute should be applied to a trait")
- .emit();
+ self.tcx.sess.emit_err(errors::ConstTrait { attr_span: attr.span });
false
}
}
fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
match target {
Target::Expression => {
- self.tcx
- .sess
- .struct_span_err(attr.span, "attribute cannot be applied to an expression")
- .emit();
+ self.tcx.sess.emit_err(errors::StabilityPromotable { attr_span: attr.span });
false
}
_ => true,
fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) {
match target {
Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build("attribute is ignored here").emit();
- });
+ self.tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ errors::Deprecated,
+ );
}
_ => {}
}
match target {
Target::ExternCrate | Target::Mod => {}
_ => {
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build(&format!(
- "`#[{name}]` only has an effect on `extern crate` and modules"
- ))
- .emit();
- });
+ self.tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ errors::MacroUse { name },
+ );
}
}
}
fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
if target != Target::MacroDef {
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build("`#[macro_export]` only has an effect on macro definitions").emit();
- });
+ self.tcx.emit_spanned_lint(UNUSED_ATTRIBUTES, hir_id, attr.span, errors::MacroExport);
}
}
fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) {
if target != Target::Fn {
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build("`#[plugin_registrar]` only has an effect on functions").emit();
- });
+ self.tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ errors::PluginRegistrar,
+ );
}
}
| sym::target_feature
) && attr.meta_item_list().map_or(false, |list| list.is_empty())
{
- format!(
- "attribute `{}` with an empty list has no effect",
- attr.name_or_empty()
- )
+ errors::UnusedNote::EmptyList { name: attr.name_or_empty() }
} else if matches!(
attr.name_or_empty(),
sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
&& let MetaItemKind::NameValue(_) = &item.kind
&& item.path == sym::reason
{
- format!(
- "attribute `{}` without any lints has no effect",
- attr.name_or_empty()
- )
+ errors::UnusedNote::NoLints { name: attr.name_or_empty() }
} else if attr.name_or_empty() == sym::default_method_body_is_const {
- format!("`default_method_body_is_const` has been replaced with `#[const_trait]` on traits")
+ errors::UnusedNote::DefaultMethodBodyConst
} else {
return;
};
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build("unused attribute")
- .span_suggestion(
- attr.span,
- "remove this attribute",
- "",
- Applicability::MachineApplicable,
- )
- .note(¬e)
- .emit();
- });
+ self.tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ errors::Unused { attr_span: attr.span, note },
+ );
}
}
for attr in attrs {
if attr.has_name(sym::inline) {
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0518,
- "attribute should be applied to function or closure",
- )
- .span_label(attr.span, "not a function or closure")
- .emit();
+ tcx.sess.emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span });
}
}
}
} else {
(attr.span, *entry.get())
};
- tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, this, |lint| {
- let mut db = lint.build("unused attribute");
- db.span_note(other, "attribute also specified here").span_suggestion(
+ tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ this,
+ errors::UnusedDuplicate {
this,
- "remove this attribute",
- "",
- Applicability::MachineApplicable,
- );
- if matches!(duplicates, FutureWarnFollowing | FutureWarnPreceding) {
- db.warn(
- "this was previously accepted by the compiler but is \
- being phased out; it will become a hard error in \
- a future release!",
- );
- }
- db.emit();
- });
+ other,
+ warning: matches!(
+ duplicates,
+ FutureWarnFollowing | FutureWarnPreceding
+ )
+ .then_some(()),
+ },
+ );
}
Entry::Vacant(entry) => {
entry.insert(attr.span);
} else {
(attr.span, *entry.get())
};
- tcx.sess
- .struct_span_err(
- this,
- &format!("multiple `{}` attributes", attr.name_or_empty()),
- )
- .span_note(other, "attribute also specified here")
- .span_suggestion(
- this,
- "remove this attribute",
- "",
- Applicability::MachineApplicable,
- )
- .emit();
+ tcx.sess.emit_err(errors::UnusedMultiple {
+ this,
+ other,
+ name: attr.name_or_empty(),
+ });
}
Entry::Vacant(entry) => {
entry.insert(attr.span);
use rustc_errors::{Applicability, MultiSpan};
-use rustc_macros::{LintDiagnostic, SessionDiagnostic};
+use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
use rustc_span::{Span, Symbol};
#[derive(LintDiagnostic)]
#[label]
pub span: Option<Span>,
}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::link_name)]
+#[warn_]
+pub struct LinkName<'a> {
+ #[help]
+ pub attr_span: Option<Span>,
+ #[label]
+ pub span: Span,
+ pub value: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::no_link)]
+pub struct NoLink {
+ #[primary_span]
+ pub attr_span: Span,
+ #[label]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::export_name)]
+pub struct ExportName {
+ #[primary_span]
+ pub attr_span: Span,
+ #[label]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_layout_scalar_valid_range_not_struct)]
+pub struct RustcLayoutScalarValidRangeNotStruct {
+ #[primary_span]
+ pub attr_span: Span,
+ #[label]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_layout_scalar_valid_range_arg)]
+pub struct RustcLayoutScalarValidRangeArg {
+ #[primary_span]
+ pub attr_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_legacy_const_generics_only)]
+pub struct RustcLegacyConstGenericsOnly {
+ #[primary_span]
+ pub attr_span: Span,
+ #[label]
+ pub param_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_legacy_const_generics_index)]
+pub struct RustcLegacyConstGenericsIndex {
+ #[primary_span]
+ pub attr_span: Span,
+ #[label]
+ pub generics_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_legacy_const_generics_index_exceed)]
+pub struct RustcLegacyConstGenericsIndexExceed {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub arg_count: usize,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_legacy_const_generics_index_negative)]
+pub struct RustcLegacyConstGenericsIndexNegative {
+ #[primary_span]
+ pub invalid_args: Vec<Span>,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_dirty_clean)]
+pub struct RustcDirtyClean {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::link_section)]
+#[warn_]
+pub struct LinkSection {
+ #[label]
+ pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::no_mangle_foreign)]
+#[warn_]
+#[note]
+pub struct NoMangleForeign {
+ #[label]
+ pub span: Span,
+ #[suggestion(applicability = "machine-applicable")]
+ pub attr_span: Span,
+ pub foreign_item_kind: &'static str,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::no_mangle)]
+#[warn_]
+pub struct NoMangle {
+ #[label]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::repr_ident, code = "E0565")]
+pub struct ReprIdent {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::repr_conflicting, code = "E0566")]
+pub struct ReprConflicting;
+
+#[derive(SessionDiagnostic)]
+#[error(passes::used_static)]
+pub struct UsedStatic {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::used_compiler_linker)]
+pub struct UsedCompilerLinker {
+ #[primary_span]
+ pub spans: Vec<Span>,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::allow_internal_unstable)]
+pub struct AllowInternalUnstable {
+ #[primary_span]
+ pub attr_span: Span,
+ #[label]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::debug_visualizer_placement)]
+pub struct DebugVisualizerPlacement {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::debug_visualizer_invalid)]
+#[note(passes::note_1)]
+#[note(passes::note_2)]
+#[note(passes::note_3)]
+pub struct DebugVisualizerInvalid {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_allow_const_fn_unstable)]
+pub struct RustcAllowConstFnUnstable {
+ #[primary_span]
+ pub attr_span: Span,
+ #[label]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_std_internal_symbol)]
+pub struct RustcStdInternalSymbol {
+ #[primary_span]
+ pub attr_span: Span,
+ #[label]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::const_trait)]
+pub struct ConstTrait {
+ #[primary_span]
+ pub attr_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::stability_promotable)]
+pub struct StabilityPromotable {
+ #[primary_span]
+ pub attr_span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::deprecated)]
+pub struct Deprecated;
+
+#[derive(LintDiagnostic)]
+#[lint(passes::macro_use)]
+pub struct MacroUse {
+ pub name: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::macro_export)]
+pub struct MacroExport;
+
+#[derive(LintDiagnostic)]
+#[lint(passes::plugin_registrar)]
+pub struct PluginRegistrar;
+
+#[derive(SessionSubdiagnostic)]
+pub enum UnusedNote {
+ #[note(passes::unused_empty_lints_note)]
+ EmptyList { name: Symbol },
+ #[note(passes::unused_no_lints_note)]
+ NoLints { name: Symbol },
+ #[note(passes::unused_default_method_body_const_note)]
+ DefaultMethodBodyConst,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::unused)]
+pub struct Unused {
+ #[suggestion(applicability = "machine-applicable")]
+ pub attr_span: Span,
+ #[subdiagnostic]
+ pub note: UnusedNote,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::non_exported_macro_invalid_attrs, code = "E0518")]
+pub struct NonExportedMacroInvalidAttrs {
+ #[primary_span]
+ #[label]
+ pub attr_span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::unused_duplicate)]
+pub struct UnusedDuplicate {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub this: Span,
+ #[note]
+ pub other: Span,
+ #[warn_]
+ pub warning: Option<()>,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::unused_multiple)]
+pub struct UnusedMultiple {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub this: Span,
+ #[note]
+ pub other: Span,
+ pub name: Symbol,
+}
//! propagating default levels lexically from parent to children ast nodes.
use attr::StabilityLevel;
-use rustc_attr::{self as attr, ConstStability, Stability, Unstable};
+use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
// while maintaining the invariant that all sysroot crates are unstable
// by default and are unable to be used.
if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
- let reason = "this crate is being loaded from the sysroot, an \
- unstable location; did you mean to load this crate \
- from crates.io via `Cargo.toml` instead?";
let stability = Stability {
level: attr::StabilityLevel::Unstable {
- reason: Some(Symbol::intern(reason)),
+ reason: UnstableReason::Default,
issue: NonZeroU32::new(27812),
is_soft: false,
implied_by: None,
let crate_root = self.r.resolve_crate_root(source.ident);
let crate_name = match crate_root.kind {
ModuleKind::Def(.., name) => name,
- ModuleKind::Block(..) => unreachable!(),
+ ModuleKind::Block => unreachable!(),
};
// HACK(eddyb) unclear how good this is, but keeping `$crate`
// in `source` breaks `src/test/ui/imports/import-crate-var.rs`,
if self.block_needs_anonymous_module(block) {
let module = self.r.new_module(
Some(parent),
- ModuleKind::Block(block.id),
+ ModuleKind::Block,
expansion.to_expn_id(),
block.span,
parent.no_implicit_prelude,
let container = match parent.kind {
ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
- ModuleKind::Block(..) => "block",
+ ModuleKind::Block => "block",
};
let old_noun = match old_binding.is_import() {
} else if let Some(sp) = sm.generate_fn_name_span(span) {
err.span_label(
sp,
- "try adding a local generic parameter in this method instead"
- .to_string(),
+ "try adding a local generic parameter in this method instead",
);
} else {
err.help("try using a local generic parameter instead");
return Some((self.expn_def_scope(ctxt.remove_mark()), None));
}
- if let ModuleKind::Block(..) = module.kind {
+ if let ModuleKind::Block = module.kind {
return Some((module.parent.unwrap().nearest_item_scope(), None));
}
};
match module.kind {
- ModuleKind::Block(..) => {} // We can see through blocks
+ ModuleKind::Block => {} // We can see through blocks
_ => break,
}
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_middle::middle::resolve_lifetime::Set1;
use rustc_middle::ty::DefIdTree;
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
/// Map from the name in a pattern to its binding mode.
type BindingMap = IdentMap<BindingInfo>;
+use diagnostics::{
+ ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime, MissingLifetimeKind,
+};
+
#[derive(Copy, Clone, Debug)]
struct BindingInfo {
span: Span,
AnonymousReportError,
/// Pass responsibility to `resolve_lifetime` code for all cases.
- AnonymousPassThrough(NodeId, /* in_fn_return */ bool),
+ AnonymousPassThrough(NodeId),
+
+ /// Replace all anonymous lifetimes by provided lifetime.
+ Elided(LifetimeRes),
+
+ /// Signal we cannot find which should be the anonymous lifetime.
+ ElisionFailure,
}
#[derive(Copy, Clone, Debug)]
/// When processing impl trait
currently_processing_impl_trait: Option<(TraitRef, Ty)>,
+
+ /// Accumulate the errors due to missed lifetime elision,
+ /// and report them all at once for each function.
+ current_elision_failures: Vec<MissingLifetime>,
}
struct LateResolutionVisitor<'a, 'b, 'ast> {
/// The current set of local scopes for lifetimes.
lifetime_ribs: Vec<LifetimeRib>,
+ /// We are looking for lifetimes in an elision context.
+ /// The set contains all the resolutions that we encountered so far.
+ /// They will be used to determine the correct lifetime for the fn return type.
+ /// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named
+ /// lifetimes.
+ lifetime_elision_candidates: Option<FxIndexMap<LifetimeRes, LifetimeElisionCandidate>>,
+
/// The trait that the current context can refer to.
current_trait_ref: Option<(Module<'a>, TraitRef)>,
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
// We deal with repeat expressions explicitly in `resolve_expr`.
self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
- this.resolve_anon_const(constant, IsRepeatExpr::No);
+ this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
+ this.resolve_anon_const(constant, IsRepeatExpr::No);
+ })
})
}
fn visit_expr(&mut self, expr: &'ast Expr) {
TyKind::Rptr(None, _) => {
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
// NodeId `ty.id`.
+ // This span will be used in case of elision failure.
let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo());
self.resolve_elided_lifetime(ty.id, span);
+ visit::walk_ty(self, ty);
}
TyKind::Path(ref qself, ref path) => {
self.diagnostic_metadata.current_type_path = Some(ty);
},
|this| this.visit_path(&path, ty.id),
);
- self.diagnostic_metadata.current_type_path = prev_ty;
- return;
+ } else {
+ visit::walk_ty(self, ty)
}
}
TyKind::ImplicitSelf => {
)
.map_or(Res::Err, |d| d.res());
self.r.record_partial_res(ty.id, PartialRes::new(res));
+ visit::walk_ty(self, ty)
+ }
+ TyKind::ImplTrait(..) => {
+ let candidates = self.lifetime_elision_candidates.take();
+ visit::walk_ty(self, ty);
+ self.lifetime_elision_candidates = candidates;
}
TyKind::TraitObject(ref bounds, ..) => {
self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
+ visit::walk_ty(self, ty)
}
TyKind::BareFn(ref bare_fn) => {
let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo());
},
|this| {
this.visit_generic_params(&bare_fn.generic_params, false);
- this.with_lifetime_rib(
- LifetimeRibKind::AnonymousCreateParameter {
- binder: ty.id,
- report_in_path: false,
- },
- |this| walk_list!(this, visit_param, &bare_fn.decl.inputs),
- );
- this.with_lifetime_rib(
- LifetimeRibKind::AnonymousPassThrough(ty.id, true),
- |this| this.visit_fn_ret_ty(&bare_fn.decl.output),
+ this.resolve_fn_signature(
+ ty.id,
+ None,
+ false,
+ // We don't need to deal with patterns in parameters, because
+ // they are not possible for foreign or bodiless functions.
+ bare_fn.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
+ &bare_fn.decl.output,
);
},
- );
- self.diagnostic_metadata.current_trait_object = prev;
- return;
+ )
}
- _ => (),
+ _ => visit::walk_ty(self, ty),
}
- visit::walk_ty(self, ty);
self.diagnostic_metadata.current_trait_object = prev;
self.diagnostic_metadata.current_type_path = prev_ty;
}
| FnKind::Fn(_, _, sig, _, generics, None) => {
self.visit_fn_header(&sig.header);
self.visit_generics(generics);
- // We don't need to deal with patterns in parameters, because
- // they are not possible for foreign or bodiless functions.
- self.with_lifetime_rib(
- LifetimeRibKind::AnonymousCreateParameter {
- binder: fn_id,
- report_in_path: false,
- },
- |this| walk_list!(this, visit_param, &sig.decl.inputs),
- );
- self.with_lifetime_rib(
- LifetimeRibKind::AnonymousPassThrough(fn_id, true),
- |this| this.visit_fn_ret_ty(&sig.decl.output),
+ self.resolve_fn_signature(
+ fn_id,
+ None,
+ sig.decl.has_self(),
+ sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
+ &sig.decl.output,
);
return;
}
let declaration = &sig.decl;
let async_node_id = sig.header.asyncness.opt_return_id();
- // Argument-position elided lifetimes must be transformed into fresh
- // generic parameters. This is especially useful for `async fn`, where
- // these fresh generic parameters can be applied to the opaque `impl Trait`
- // return type.
- this.with_lifetime_rib(
- LifetimeRibKind::AnonymousCreateParameter {
- binder: fn_id,
- // Only emit a hard error for `async fn`, since this kind of
- // elision has always been allowed in regular `fn`s.
- report_in_path: async_node_id.is_some(),
- },
- // Add each argument to the rib.
- |this| this.resolve_params(&declaration.inputs),
+ this.resolve_fn_signature(
+ fn_id,
+ async_node_id,
+ declaration.has_self(),
+ declaration
+ .inputs
+ .iter()
+ .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)),
+ &declaration.output,
);
// Construct the list of in-scope lifetime parameters for async lowering.
.insert(async_node_id, extra_lifetime_params);
}
- this.with_lifetime_rib(
- LifetimeRibKind::AnonymousPassThrough(
- // For async fn, the return type appears inside a custom
- // `impl Future` RPIT, so we override the binder's id.
- async_node_id.unwrap_or(fn_id),
- true,
- ),
- |this| visit::walk_fn_ret_ty(this, &declaration.output),
- );
-
if let Some(body) = body {
// Ignore errors in function bodies if this is rustdoc
// Be sure not to set this until the function signature has been resolved.
let previous_state = replace(&mut this.in_func_body, true);
// Resolve the function body, potentially inside the body of an async closure
this.with_lifetime_rib(
- LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+ LifetimeRibKind::AnonymousPassThrough(fn_id),
|this| this.visit_block(body),
);
this.with_lifetime_rib(
match binder {
ClosureBinder::NotPresent => {
- LifetimeRibKind::AnonymousPassThrough(fn_id, true)
+ LifetimeRibKind::AnonymousPassThrough(fn_id)
}
ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError,
},
let previous_state = replace(&mut this.in_func_body, true);
// Resolve the function body, potentially inside the body of an async closure
this.with_lifetime_rib(
- LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+ LifetimeRibKind::AnonymousPassThrough(fn_id),
|this| this.visit_expr(body),
);
kind: LifetimeBinderKind::PolyTrait,
..
} => {
- self.with_lifetime_rib(
- LifetimeRibKind::AnonymousCreateParameter {
- binder,
- report_in_path: false,
- },
- |this| walk_list!(this, visit_ty, &p_args.inputs),
- );
- self.with_lifetime_rib(
- LifetimeRibKind::AnonymousPassThrough(binder, true),
- |this| visit::walk_fn_ret_ty(this, &p_args.output),
+ self.resolve_fn_signature(
+ binder,
+ None,
+ false,
+ p_args.inputs.iter().map(|ty| (None, &**ty)),
+ &p_args.output,
);
break;
}
LifetimeRibKind::AnonymousPassThrough(..)
| LifetimeRibKind::AnonymousCreateParameter { .. }
| LifetimeRibKind::AnonymousReportError
+ | LifetimeRibKind::Elided(_)
+ | LifetimeRibKind::ElisionFailure
| LifetimeRibKind::AnonConst
| LifetimeRibKind::ConstGeneric => {}
}
},
label_ribs: Vec::new(),
lifetime_ribs: Vec::new(),
+ lifetime_elision_candidates: None,
current_trait_ref: None,
diagnostic_metadata: Box::new(DiagnosticMetadata::default()),
// errors at module scope should always be reported
work: impl FnOnce(&mut Self) -> T,
) -> T {
self.lifetime_ribs.push(LifetimeRib::new(kind));
+ let outer_elision_candidates = self.lifetime_elision_candidates.take();
let ret = work(self);
+ self.lifetime_elision_candidates = outer_elision_candidates;
self.lifetime_ribs.pop();
ret
}
let ident = lifetime.ident;
if ident.name == kw::StaticLifetime {
- self.record_lifetime_res(lifetime.id, LifetimeRes::Static);
+ self.record_lifetime_res(
+ lifetime.id,
+ LifetimeRes::Static,
+ LifetimeElisionCandidate::Named,
+ );
return;
}
let rib = &self.lifetime_ribs[i];
let normalized_ident = ident.normalize_to_macros_2_0();
if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
- self.record_lifetime_res(lifetime.id, res);
+ self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named);
if let LifetimeRes::Param { param, .. } = res {
match self.lifetime_uses.entry(param) {
// Do not suggest eliding a lifetime where an anonymous
// lifetime would be illegal.
LifetimeRibKind::Item
- | LifetimeRibKind::AnonymousPassThrough(_, true)
- | LifetimeRibKind::AnonymousReportError => {
- Some(LifetimeUseSet::Many)
- }
+ | LifetimeRibKind::AnonymousReportError
+ | LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many),
// An anonymous lifetime is legal here, go ahead.
- LifetimeRibKind::AnonymousPassThrough(_, false)
+ LifetimeRibKind::AnonymousPassThrough(_)
| LifetimeRibKind::AnonymousCreateParameter { .. } => {
Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
}
+ // Only report if eliding the lifetime would have the same
+ // semantics.
+ LifetimeRibKind::Elided(r) => Some(if res == r {
+ LifetimeUseSet::One { use_span: ident.span, use_ctxt }
+ } else {
+ LifetimeUseSet::Many
+ }),
LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ConstGeneric
| LifetimeRibKind::AnonConst => None,
LifetimeRibKind::Item => break,
LifetimeRibKind::ConstGeneric => {
self.emit_non_static_lt_in_const_generic_error(lifetime);
- self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error);
+ self.record_lifetime_res(
+ lifetime.id,
+ LifetimeRes::Error,
+ LifetimeElisionCandidate::Ignore,
+ );
return;
}
LifetimeRibKind::AnonConst => {
self.maybe_emit_forbidden_non_static_lifetime_error(lifetime);
- self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error);
+ self.record_lifetime_res(
+ lifetime.id,
+ LifetimeRes::Error,
+ LifetimeElisionCandidate::Ignore,
+ );
return;
}
_ => {}
}
self.emit_undeclared_lifetime_error(lifetime, outer_res);
- self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
+ self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named);
}
#[tracing::instrument(level = "debug", skip(self))]
fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
+ let missing_lifetime = MissingLifetime {
+ id: lifetime.id,
+ span: lifetime.ident.span,
+ kind: if elided {
+ MissingLifetimeKind::Ampersand
+ } else {
+ MissingLifetimeKind::Underscore
+ },
+ count: 1,
+ };
+ let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
for i in (0..self.lifetime_ribs.len()).rev() {
let rib = &mut self.lifetime_ribs[i];
+ debug!(?rib.kind);
match rib.kind {
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder);
- self.record_lifetime_res(lifetime.id, res);
+ self.record_lifetime_res(lifetime.id, res, elision_candidate);
return;
}
LifetimeRibKind::AnonymousReportError => {
.span_label(lifetime.ident.span, note)
.emit();
- self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
+ self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
return;
}
- LifetimeRibKind::AnonymousPassThrough(node_id, _) => {
+ LifetimeRibKind::AnonymousPassThrough(node_id) => {
self.record_lifetime_res(
lifetime.id,
LifetimeRes::Anonymous { binder: node_id, elided },
+ elision_candidate,
);
return;
}
+ LifetimeRibKind::Elided(res) => {
+ self.record_lifetime_res(lifetime.id, res, elision_candidate);
+ return;
+ }
+ LifetimeRibKind::ElisionFailure => {
+ self.diagnostic_metadata.current_elision_failures.push(missing_lifetime);
+ self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
+ return;
+ }
LifetimeRibKind::Item => break,
LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ConstGeneric
| LifetimeRibKind::AnonConst => {}
}
}
- // This resolution is wrong, it passes the work to HIR lifetime resolution.
- // We cannot use `LifetimeRes::Error` because we do not emit a diagnostic.
- self.record_lifetime_res(
- lifetime.id,
- LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided },
- );
+ self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
+ self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
}
#[tracing::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.record_lifetime_res(
anchor_id,
LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) },
+ LifetimeElisionCandidate::Ignore,
);
-
- let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
self.resolve_anonymous_lifetime(<, true);
}
self.record_lifetime_res(
segment_id,
LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
+ LifetimeElisionCandidate::Ignore,
);
if !missing {
// Do not create a parameter for patterns and expressions.
for rib in self.lifetime_ribs.iter().rev() {
match rib.kind {
- LifetimeRibKind::AnonymousPassThrough(binder, _) => {
+ LifetimeRibKind::AnonymousPassThrough(binder) => {
let res = LifetimeRes::Anonymous { binder, elided: true };
for id in node_ids {
- self.record_lifetime_res(id, res);
+ self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named);
}
break;
}
let res =
LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
for id in node_ids {
- self.record_lifetime_res(id, res);
+ self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named);
}
break;
}
LifetimeRibKind::AnonymousCreateParameter { .. }
+ | LifetimeRibKind::Elided(_)
+ | LifetimeRibKind::ElisionFailure
| LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ConstGeneric
| LifetimeRibKind::AnonConst => {}
continue;
}
+ let missing_lifetime = MissingLifetime {
+ id: node_ids.start,
+ span: elided_lifetime_span,
+ kind: if segment.has_generic_args {
+ MissingLifetimeKind::Comma
+ } else {
+ MissingLifetimeKind::Brackets
+ },
+ count: expected_lifetimes,
+ };
let mut should_lint = true;
for rib in self.lifetime_ribs.iter().rev() {
match rib.kind {
should_lint = false;
for id in node_ids {
- self.record_lifetime_res(id, LifetimeRes::Error);
+ self.record_lifetime_res(
+ id,
+ LifetimeRes::Error,
+ LifetimeElisionCandidate::Named,
+ );
}
break;
}
// Do not create a parameter for patterns and expressions.
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
+ // Group all suggestions into the first record.
+ let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
for id in node_ids {
let res = self.create_fresh_lifetime(id, ident, binder);
- self.record_lifetime_res(id, res);
+ self.record_lifetime_res(
+ id,
+ res,
+ replace(&mut candidate, LifetimeElisionCandidate::Named),
+ );
}
break;
}
// `PassThrough` is the normal case.
- LifetimeRibKind::AnonymousPassThrough(binder, _) => {
+ LifetimeRibKind::AnonymousPassThrough(binder) => {
let res = LifetimeRes::Anonymous { binder, elided: true };
+ let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
for id in node_ids {
- self.record_lifetime_res(id, res);
+ self.record_lifetime_res(
+ id,
+ res,
+ replace(&mut candidate, LifetimeElisionCandidate::Ignore),
+ );
+ }
+ break;
+ }
+ LifetimeRibKind::Elided(res) => {
+ let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
+ for id in node_ids {
+ self.record_lifetime_res(
+ id,
+ res,
+ replace(&mut candidate, LifetimeElisionCandidate::Ignore),
+ );
+ }
+ break;
+ }
+ LifetimeRibKind::ElisionFailure => {
+ self.diagnostic_metadata.current_elision_failures.push(missing_lifetime);
+ for id in node_ids {
+ self.record_lifetime_res(
+ id,
+ LifetimeRes::Error,
+ LifetimeElisionCandidate::Ignore,
+ );
}
break;
}
// we simply resolve to an implicit lifetime, which will be checked later, at
// which point a suitable error will be emitted.
LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
- // FIXME(cjgillot) This resolution is wrong, but this does not matter
- // since these cases are erroneous anyway. Lifetime resolution should
- // emit a "missing lifetime specifier" diagnostic.
- let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
for id in node_ids {
- self.record_lifetime_res(id, res);
+ self.record_lifetime_res(
+ id,
+ LifetimeRes::Error,
+ LifetimeElisionCandidate::Ignore,
+ );
}
+ self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
break;
}
LifetimeRibKind::Generics { .. }
}
#[tracing::instrument(level = "debug", skip(self))]
- fn record_lifetime_res(&mut self, id: NodeId, res: LifetimeRes) {
+ fn record_lifetime_res(
+ &mut self,
+ id: NodeId,
+ res: LifetimeRes,
+ candidate: LifetimeElisionCandidate,
+ ) {
if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
panic!(
"lifetime {:?} resolved multiple times ({:?} before, {:?} now)",
id, prev_res, res
)
}
+ match res {
+ LifetimeRes::Param { .. }
+ | LifetimeRes::Fresh { .. }
+ | LifetimeRes::Anonymous { .. }
+ | LifetimeRes::Static => {
+ if let Some(ref mut candidates) = self.lifetime_elision_candidates {
+ candidates.insert(res, candidate);
+ }
+ }
+ LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {}
+ }
+ }
+
+ #[tracing::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!(
+ "lifetime parameter {:?} resolved multiple times ({:?} before, {:?} now)",
+ id, prev_res, res
+ )
+ }
+ }
+
+ /// Perform resolution of a function signature, accounting for lifetime elision.
+ #[tracing::instrument(level = "debug", skip(self, inputs))]
+ fn resolve_fn_signature(
+ &mut self,
+ fn_id: NodeId,
+ async_node_id: Option<NodeId>,
+ has_self: bool,
+ inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)> + Clone,
+ output_ty: &'ast FnRetTy,
+ ) {
+ // Add each argument to the rib.
+ let parameter_rib = LifetimeRibKind::AnonymousCreateParameter {
+ binder: fn_id,
+ report_in_path: async_node_id.is_some(),
+ };
+ let elision_lifetime =
+ self.with_lifetime_rib(parameter_rib, |this| this.resolve_fn_params(has_self, inputs));
+ debug!(?elision_lifetime);
+
+ let outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures);
+ let output_rib = if let Ok(res) = elision_lifetime.as_ref() {
+ LifetimeRibKind::Elided(*res)
+ } else {
+ LifetimeRibKind::ElisionFailure
+ };
+ self.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, &output_ty));
+ let elision_failures =
+ replace(&mut self.diagnostic_metadata.current_elision_failures, outer_failures);
+ if !elision_failures.is_empty() {
+ let Err(failure_info) = elision_lifetime else { bug!() };
+ self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info));
+ }
+ }
+
+ /// Resolve inside function parameters and parameter types.
+ /// Returns the lifetime for elision in fn return type,
+ /// or diagnostic information in case of elision failure.
+ fn resolve_fn_params(
+ &mut self,
+ has_self: bool,
+ inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)>,
+ ) -> Result<LifetimeRes, (Vec<MissingLifetime>, Vec<ElisionFnParameter>)> {
+ let outer_candidates =
+ replace(&mut self.lifetime_elision_candidates, Some(Default::default()));
+
+ let mut elision_lifetime = None;
+ let mut lifetime_count = 0;
+ let mut parameter_info = Vec::new();
+
+ let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
+ for (index, (pat, ty)) in inputs.enumerate() {
+ debug!(?pat, ?ty);
+ if let Some(pat) = pat {
+ self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+ }
+ self.visit_ty(ty);
+
+ if let Some(ref candidates) = self.lifetime_elision_candidates {
+ let new_count = candidates.len();
+ let local_count = new_count - lifetime_count;
+ if local_count != 0 {
+ parameter_info.push(ElisionFnParameter {
+ index,
+ ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind {
+ Some(ident)
+ } else {
+ None
+ },
+ lifetime_count: local_count,
+ span: ty.span,
+ });
+ }
+ lifetime_count = new_count;
+ }
+
+ // Handle `self` specially.
+ if index == 0 && has_self {
+ let self_lifetime = self.find_lifetime_for_self(ty);
+ if let Set1::One(lifetime) = self_lifetime {
+ elision_lifetime = Some(lifetime);
+ self.lifetime_elision_candidates = None;
+ } else {
+ self.lifetime_elision_candidates = Some(Default::default());
+ lifetime_count = 0;
+ }
+ }
+ debug!("(resolving function / closure) recorded parameter");
+ }
+
+ let all_candidates = replace(&mut self.lifetime_elision_candidates, outer_candidates);
+ debug!(?all_candidates);
+
+ if let Some(res) = elision_lifetime {
+ return Ok(res);
+ }
+
+ // We do not have a `self` candidate, look at the full list.
+ let all_candidates = all_candidates.unwrap();
+ if all_candidates.len() == 1 {
+ Ok(*all_candidates.first().unwrap().0)
+ } else {
+ let all_candidates = all_candidates
+ .into_iter()
+ .filter_map(|(_, candidate)| match candidate {
+ LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => None,
+ LifetimeElisionCandidate::Missing(missing) => Some(missing),
+ })
+ .collect();
+ Err((all_candidates, parameter_info))
+ }
+ }
+
+ /// List all the lifetimes that appear in the provided type.
+ fn find_lifetime_for_self(&self, ty: &'ast Ty) -> Set1<LifetimeRes> {
+ struct SelfVisitor<'r, 'a> {
+ r: &'r Resolver<'a>,
+ impl_self: Option<Res>,
+ lifetime: Set1<LifetimeRes>,
+ }
+
+ impl SelfVisitor<'_, '_> {
+ // Look for `self: &'a Self` - also desugared from `&'a self`,
+ // and if that matches, use it for elision and return early.
+ fn is_self_ty(&self, ty: &Ty) -> bool {
+ match ty.kind {
+ TyKind::ImplicitSelf => true,
+ TyKind::Path(None, _) => {
+ let path_res = self.r.partial_res_map[&ty.id].base_res();
+ if let Res::SelfTy { .. } = path_res {
+ return true;
+ }
+ Some(path_res) == self.impl_self
+ }
+ _ => false,
+ }
+ }
+ }
+
+ impl<'a> Visitor<'a> for SelfVisitor<'_, '_> {
+ fn visit_ty(&mut self, ty: &'a Ty) {
+ trace!("SelfVisitor considering ty={:?}", ty);
+ if let TyKind::Rptr(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) {
+ let lt_id = if let Some(lt) = lt {
+ lt.id
+ } else {
+ let res = self.r.lifetimes_res_map[&ty.id];
+ let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() };
+ start
+ };
+ let lt_res = self.r.lifetimes_res_map[<_id];
+ trace!("SelfVisitor inserting res={:?}", lt_res);
+ self.lifetime.insert(lt_res);
+ }
+ visit::walk_ty(self, ty)
+ }
+ }
+
+ let impl_self = self
+ .diagnostic_metadata
+ .current_self_type
+ .as_ref()
+ .and_then(|ty| {
+ if let TyKind::Path(None, _) = ty.kind {
+ self.r.partial_res_map.get(&ty.id)
+ } else {
+ None
+ }
+ })
+ .map(|res| res.base_res())
+ .filter(|res| {
+ // Permit the types that unambiguously always
+ // result in the same type constructor being used
+ // (it can't differ between `Self` and `self`).
+ matches!(
+ res,
+ Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
+ )
+ });
+ let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
+ visitor.visit_ty(ty);
+ trace!("SelfVisitor found={:?}", visitor.lifetime);
+ visitor.lifetime
}
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
self.with_item_rib(|this| {
- this.visit_ty(ty);
- if let Some(expr) = expr {
- let constant_item_kind = match item.kind {
- ItemKind::Const(..) => ConstantItemKind::Const,
- ItemKind::Static(..) => ConstantItemKind::Static,
- _ => unreachable!(),
- };
- // We already forbid generic params because of the above item rib,
- // so it doesn't matter whether this is a trivial constant.
- this.with_constant_rib(
- IsRepeatExpr::No,
- HasGenericParams::Yes,
- Some((item.ident, constant_item_kind)),
- |this| this.visit_expr(expr),
- );
- }
+ this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
+ this.visit_ty(ty);
+ });
+ this.with_lifetime_rib(
+ LifetimeRibKind::AnonymousPassThrough(item.id),
+ |this| {
+ if let Some(expr) = expr {
+ let constant_item_kind = match item.kind {
+ ItemKind::Const(..) => ConstantItemKind::Const,
+ ItemKind::Static(..) => ConstantItemKind::Static,
+ _ => unreachable!(),
+ };
+ // We already forbid generic params because of the above item rib,
+ // so it doesn't matter whether this is a trivial constant.
+ this.with_constant_rib(
+ IsRepeatExpr::No,
+ HasGenericParams::Yes,
+ Some((item.ident, constant_item_kind)),
+ |this| this.visit_expr(expr),
+ );
+ }
+ },
+ );
});
}
{
diagnostics::signal_lifetime_shadowing(self.r.session, original, param.ident);
// Record lifetime res, so lowering knows there is something fishy.
- self.record_lifetime_res(param.id, LifetimeRes::Error);
+ self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
}
self.report_error(param.ident.span, err);
if let GenericParamKind::Lifetime = param.kind {
// Record lifetime res, so lowering knows there is something fishy.
- self.record_lifetime_res(param.id, LifetimeRes::Error);
+ self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
}
}
.span_label(param.ident.span, "`'_` is a reserved lifetime name")
.emit();
// Record lifetime res, so lowering knows there is something fishy.
- self.record_lifetime_res(param.id, LifetimeRes::Error);
+ self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
}
.span_label(param.ident.span, "'static is a reserved lifetime name")
.emit();
// Record lifetime res, so lowering knows there is something fishy.
- self.record_lifetime_res(param.id, LifetimeRes::Error);
+ self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
}
GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
GenericParamKind::Lifetime => {
let res = LifetimeRes::Param { param: def_id, binder };
- self.record_lifetime_res(param.id, res);
+ self.record_lifetime_param(param.id, res);
function_lifetime_rib.bindings.insert(ident, (param.id, res));
continue;
}
self.ribs[TypeNS].pop();
self.ribs[ValueNS].pop();
- self.lifetime_ribs.pop();
+ let function_lifetime_rib = self.lifetime_ribs.pop().unwrap();
+
+ // Do not account for the parameters we just bound for function lifetime elision.
+ if let Some(ref mut candidates) = self.lifetime_elision_candidates {
+ for (_, res) in function_lifetime_rib.bindings.values() {
+ candidates.remove(res);
+ }
+ }
if let LifetimeBinderKind::BareFnType
| LifetimeBinderKind::WhereBound
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
- self.with_constant_rib(
- IsRepeatExpr::No,
- HasGenericParams::Yes,
- None,
- |this| this.visit_expr(expr),
+ self.with_lifetime_rib(
+ LifetimeRibKind::AnonymousPassThrough(item.id),
+ |this| {
+ this.with_constant_rib(
+ IsRepeatExpr::No,
+ HasGenericParams::Yes,
+ None,
+ |this| this.visit_expr(expr),
+ )
+ },
);
}
}
AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
}
- AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
- walk_assoc_item(self, generics, LifetimeBinderKind::Item, item);
- }
+ AssocItemKind::TyAlias(box TyAlias { generics, .. }) => self
+ .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+ walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
+ }),
AssocItemKind::MacCall(_) => {
panic!("unexpanded macro in resolve!")
}
LifetimeRibKind::Generics {
span: generics.span,
binder: item_id,
- kind: LifetimeBinderKind::ImplBlock
+ kind: LifetimeBinderKind::ImplBlock,
},
|this| {
// Dummy self type for better errors if `Self` is used in the trait path.
// Register the trait definitions from here.
if let Some(trait_id) = trait_id {
- this.r.trait_impls.entry(trait_id).or_default().push(item_def_id);
+ this.r
+ .trait_impls
+ .entry(trait_id)
+ .or_default()
+ .push(item_def_id);
}
let item_def_id = item_def_id.to_def_id();
this.visit_generics(generics);
// Resolve the items within the impl.
- this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id,false),
- |this| {
- this.with_current_self_type(self_type, |this| {
- this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
- debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
- for item in impl_items {
- this.resolve_impl_item(&**item);
- }
- });
- });
- },
- );
+ this.with_current_self_type(self_type, |this| {
+ this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
+ debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
+ for item in impl_items {
+ this.resolve_impl_item(&**item);
+ }
+ });
+ });
});
},
- );
+ )
},
);
});
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
- self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
- this.visit_expr(expr)
- });
+ self.with_lifetime_rib(
+ LifetimeRibKind::AnonymousPassThrough(item.id),
+ |this| {
+ this.with_constant_rib(
+ IsRepeatExpr::No,
+ HasGenericParams::Yes,
+ None,
+ |this| this.visit_expr(expr),
+ )
+ },
+ );
}
}
AssocItemKind::Fn(box Fn { generics, .. }) => {
kind: LifetimeBinderKind::Item,
},
|this| {
- // If this is a trait impl, ensure the type
- // exists in trait
- this.check_trait_item(
- item.id,
- item.ident,
- &item.kind,
- TypeNS,
- item.span,
- |i, s, c| TypeNotMemberOfTrait(i, s, c),
- );
+ this.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+ // If this is a trait impl, ensure the type
+ // exists in trait
+ this.check_trait_item(
+ item.id,
+ item.ident,
+ &item.kind,
+ TypeNS,
+ item.span,
+ |i, s, c| TypeNotMemberOfTrait(i, s, c),
+ );
- visit::walk_assoc_item(this, item, AssocCtxt::Impl)
+ visit::walk_assoc_item(this, item, AssocCtxt::Impl)
+ });
},
);
}
ExprKind::Repeat(ref elem, ref ct) => {
self.visit_expr(elem);
self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
- this.resolve_anon_const(ct, IsRepeatExpr::Yes)
+ this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
+ this.resolve_anon_const(ct, IsRepeatExpr::Yes)
+ })
});
}
ExprKind::ConstBlock(ref ct) => {
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
-use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
-use crate::late::{LifetimeBinderKind, LifetimeRibKind, LifetimeUseSet};
+use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet};
use crate::path_names_to_string;
use crate::{Module, ModuleKind, ModuleOrUniformRoot};
use crate::{PathResult, PathSource, Segment};
use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt};
use rustc_ast::{
self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind,
- NodeId, Path, Ty, TyKind,
+ NodeId, Path, Ty, TyKind, DUMMY_NODE_ID,
};
use rustc_ast_pretty::pprust::path_segment_to_string;
-use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
MultiSpan,
use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::hygiene::MacroKind;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, Span};
use std::iter;
use std::ops::Deref;
}
}
-pub(crate) enum MissingLifetimeSpot<'tcx> {
- Generics(&'tcx hir::Generics<'tcx>),
- HigherRanked { span: Span, span_type: ForLifetimeSpanType },
- Static,
-}
-
-pub(crate) enum ForLifetimeSpanType {
- BoundEmpty,
- BoundTail,
- TypeEmpty,
- TypeTail,
- ClosureEmpty,
- ClosureTail,
-}
-
-impl ForLifetimeSpanType {
- pub(crate) fn descr(&self) -> &'static str {
- match self {
- Self::BoundEmpty | Self::BoundTail => "bound",
- Self::TypeEmpty | Self::TypeTail => "type",
- Self::ClosureEmpty | Self::ClosureTail => "closure",
- }
- }
-
- pub(crate) fn suggestion(&self, sugg: impl std::fmt::Display) -> String {
- match self {
- Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
- Self::ClosureEmpty => format!("for<{}>", sugg),
- Self::BoundTail | Self::TypeTail | Self::ClosureTail => format!(", {}", sugg),
- }
- }
-}
-
-impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &&'tcx hir::Generics<'tcx> {
- fn into(self) -> MissingLifetimeSpot<'tcx> {
- MissingLifetimeSpot::Generics(self)
- }
-}
-
fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
}
(variant_path_string, enum_path_string)
}
+/// Description of an elided lifetime.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub(super) struct MissingLifetime {
+ /// Used to overwrite the resolution with the suggestion, to avoid cascasing errors.
+ pub id: NodeId,
+ /// Where to suggest adding the lifetime.
+ pub span: Span,
+ /// How the lifetime was introduced, to have the correct space and comma.
+ pub kind: MissingLifetimeKind,
+ /// Number of elided lifetimes, used for elision in path.
+ pub count: usize,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub(super) enum MissingLifetimeKind {
+ /// An explicit `'_`.
+ Underscore,
+ /// An elided lifetime `&' ty`.
+ Ampersand,
+ /// An elided lifetime in brackets with written brackets.
+ Comma,
+ /// An elided lifetime with elided brackets.
+ Brackets,
+}
+
+/// Description of the lifetimes appearing in a function parameter.
+/// This is used to provide a literal explanation to the elision failure.
+#[derive(Clone, Debug)]
+pub(super) struct ElisionFnParameter {
+ /// The index of the argument in the original definition.
+ pub index: usize,
+ /// The name of the argument if it's a simple ident.
+ pub ident: Option<Ident>,
+ /// The number of lifetimes in the parameter.
+ pub lifetime_count: usize,
+ /// The span of the parameter.
+ pub span: Span,
+}
+
+/// Description of lifetimes that appear as candidates for elision.
+/// This is used to suggest introducing an explicit lifetime.
+#[derive(Debug)]
+pub(super) enum LifetimeElisionCandidate {
+ /// This is not a real lifetime.
+ Ignore,
+ /// There is a named lifetime, we won't suggest anything.
+ Named,
+ Missing(MissingLifetime),
+}
+
impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
fn def_span(&self, def_id: DefId) -> Option<Span> {
match def_id.krate {
// Items from this module
self.r.add_module_candidates(module, &mut names, &filter_fn);
- if let ModuleKind::Block(..) = module.kind {
+ if let ModuleKind::Block = module.kind {
// We can see through blocks
} else {
// Items from the prelude
err.span_label(lifetime_ref.ident.span, "undeclared lifetime");
err
};
- let mut suggest_note = true;
+ self.suggest_introducing_lifetime(
+ &mut err,
+ Some(lifetime_ref.ident.name.as_str()),
+ |err, _, span, message, suggestion| {
+ err.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect);
+ true
+ },
+ );
+ err.emit();
+ }
+ fn suggest_introducing_lifetime(
+ &self,
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ name: Option<&str>,
+ suggest: impl Fn(&mut DiagnosticBuilder<'_, ErrorGuaranteed>, bool, Span, &str, String) -> bool,
+ ) {
+ let mut suggest_note = true;
for rib in self.lifetime_ribs.iter().rev() {
+ let mut should_continue = true;
match rib.kind {
LifetimeRibKind::Generics { binder: _, span, kind } => {
- if !span.can_be_used_for_suggestions() && suggest_note {
+ if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name {
suggest_note = false; // Avoid displaying the same help multiple times.
err.span_label(
span,
&format!(
"lifetime `{}` is missing in item created through this procedural macro",
- lifetime_ref.ident,
+ name,
),
);
continue;
let sugg = format!(
"{}<{}>{}",
if higher_ranked { "for" } else { "" },
- lifetime_ref.ident,
+ name.unwrap_or("'a"),
if higher_ranked { " " } else { "" },
);
(span, sugg)
} else {
let span =
self.r.session.source_map().span_through_char(span, '<').shrink_to_hi();
- let sugg = format!("{}, ", lifetime_ref.ident);
+ let sugg = format!("{}, ", name.unwrap_or("'a"));
(span, sugg)
};
if higher_ranked {
- err.span_suggestion(
- span,
- &format!(
- "consider making the {} lifetime-generic with a new `{}` lifetime",
- kind.descr(),
- lifetime_ref
- ),
- sugg,
- Applicability::MaybeIncorrect,
+ let message = format!(
+ "consider making the {} lifetime-generic with a new `{}` lifetime",
+ kind.descr(),
+ name.unwrap_or("'a"),
);
+ should_continue = suggest(err, true, span, &message, sugg);
err.note_once(
"for more information on higher-ranked polymorphism, visit \
https://doc.rust-lang.org/nomicon/hrtb.html",
);
+ } else if let Some(name) = name {
+ let message = format!("consider introducing lifetime `{}` here", name);
+ should_continue = suggest(err, false, span, &message, sugg);
} else {
- err.span_suggestion(
- span,
- &format!("consider introducing lifetime `{}` here", lifetime_ref.ident),
- sugg,
- Applicability::MaybeIncorrect,
- );
+ let message = format!("consider introducing a named lifetime parameter");
+ should_continue = suggest(err, false, span, &message, sugg);
}
}
LifetimeRibKind::Item => break,
_ => {}
}
+ if !should_continue {
+ break;
+ }
}
-
- err.emit();
}
pub(crate) fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &ast::Lifetime) {
.emit();
}
}
-}
-/// Report lifetime/lifetime shadowing as an error.
-pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
- let mut err = struct_span_err!(
- sess,
- shadower.span,
- E0496,
- "lifetime name `{}` shadows a lifetime name that is already in scope",
- orig.name,
- );
- err.span_label(orig.span, "first declared here");
- err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name));
- err.emit();
-}
-
-/// Shadowing involving a label is only a warning for historical reasons.
-//FIXME: make this a proper lint.
-pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
- let name = shadower.name;
- let shadower = shadower.span;
- let mut err = sess.struct_span_warn(
- shadower,
- &format!("label name `{}` shadows a label name that is already in scope", name),
- );
- err.span_label(orig, "first declared here");
- err.span_label(shadower, format!("label `{}` already in scope", name));
- err.emit();
-}
-
-impl<'tcx> LifetimeContext<'_, 'tcx> {
pub(crate) fn report_missing_lifetime_specifiers(
- &self,
- spans: Vec<Span>,
- count: usize,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- struct_span_err!(
- self.tcx.sess,
+ &mut self,
+ lifetime_refs: Vec<MissingLifetime>,
+ function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
+ ) -> ErrorGuaranteed {
+ let num_lifetimes: usize = lifetime_refs.iter().map(|lt| lt.count).sum();
+ let spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
+
+ let mut err = struct_span_err!(
+ self.r.session,
spans,
E0106,
"missing lifetime specifier{}",
- pluralize!(count)
- )
+ pluralize!(num_lifetimes)
+ );
+ self.add_missing_lifetime_specifiers_label(
+ &mut err,
+ lifetime_refs,
+ function_param_lifetimes,
+ );
+ err.emit()
}
- /// Returns whether to add `'static` lifetime to the suggested lifetime list.
- pub(crate) fn report_elision_failure(
- &self,
- diag: &mut Diagnostic,
- params: &[ElisionFailureInfo],
- ) -> bool {
- let mut m = String::new();
- let len = params.len();
+ pub(crate) fn add_missing_lifetime_specifiers_label(
+ &mut self,
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ lifetime_refs: Vec<MissingLifetime>,
+ function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
+ ) {
+ for < in &lifetime_refs {
+ err.span_label(
+ lt.span,
+ format!(
+ "expected {} lifetime parameter{}",
+ if lt.count == 1 { "named".to_string() } else { lt.count.to_string() },
+ pluralize!(lt.count),
+ ),
+ );
+ }
- let elided_params: Vec<_> =
- params.iter().cloned().filter(|info| info.lifetime_count > 0).collect();
+ let mut in_scope_lifetimes: Vec<_> = self
+ .lifetime_ribs
+ .iter()
+ .rev()
+ .take_while(|rib| !matches!(rib.kind, LifetimeRibKind::Item))
+ .flat_map(|rib| rib.bindings.iter())
+ .map(|(&ident, &res)| (ident, res))
+ .filter(|(ident, _)| ident.name != kw::UnderscoreLifetime)
+ .collect();
+ debug!(?in_scope_lifetimes);
- let elided_len = elided_params.len();
+ debug!(?function_param_lifetimes);
+ if let Some((param_lifetimes, params)) = &function_param_lifetimes {
+ let elided_len = param_lifetimes.len();
+ let num_params = params.len();
- for (i, info) in elided_params.into_iter().enumerate() {
- let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } =
- info;
+ let mut m = String::new();
- diag.span_label(span, "");
- let help_name = if let Some(ident) =
- parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident())
- {
- format!("`{}`", ident)
- } else {
- format!("argument {}", index + 1)
- };
+ for (i, info) in params.iter().enumerate() {
+ let ElisionFnParameter { ident, index, lifetime_count, span } = *info;
+ debug_assert_ne!(lifetime_count, 0);
- m.push_str(
- &(if n == 1 {
- help_name
+ err.span_label(span, "");
+
+ if i != 0 {
+ if i + 1 < num_params {
+ m.push_str(", ");
+ } else if num_params == 2 {
+ m.push_str(" or ");
+ } else {
+ m.push_str(", or ");
+ }
+ }
+
+ let help_name = if let Some(ident) = ident {
+ format!("`{}`", ident)
} else {
- format!(
- "one of {}'s {} {}lifetimes",
- help_name,
- n,
- if have_bound_regions { "free " } else { "" }
- )
- })[..],
- );
+ format!("argument {}", index + 1)
+ };
- if elided_len == 2 && i == 0 {
- m.push_str(" or ");
- } else if i + 2 == elided_len {
- m.push_str(", or ");
- } else if i != elided_len - 1 {
- m.push_str(", ");
+ if lifetime_count == 1 {
+ m.push_str(&help_name[..])
+ } else {
+ m.push_str(&format!("one of {}'s {} lifetimes", help_name, lifetime_count)[..])
+ }
}
- }
- if len == 0 {
- diag.help(
- "this function's return type contains a borrowed value, \
+ if num_params == 0 {
+ err.help(
+ "this function's return type contains a borrowed value, \
but there is no value for it to be borrowed from",
- );
- true
- } else if elided_len == 0 {
- diag.help(
- "this function's return type contains a borrowed value with \
+ );
+ if in_scope_lifetimes.is_empty() {
+ in_scope_lifetimes = vec![(
+ Ident::with_dummy_span(kw::StaticLifetime),
+ (DUMMY_NODE_ID, LifetimeRes::Static),
+ )];
+ }
+ } else if elided_len == 0 {
+ err.help(
+ "this function's return type contains a borrowed value with \
an elided lifetime, but the lifetime cannot be derived from \
the arguments",
- );
- true
- } else if elided_len == 1 {
- diag.help(&format!(
- "this function's return type contains a borrowed value, \
+ );
+ if in_scope_lifetimes.is_empty() {
+ in_scope_lifetimes = vec![(
+ Ident::with_dummy_span(kw::StaticLifetime),
+ (DUMMY_NODE_ID, LifetimeRes::Static),
+ )];
+ }
+ } else if num_params == 1 {
+ err.help(&format!(
+ "this function's return type contains a borrowed value, \
but the signature does not say which {} it is borrowed from",
- m
- ));
- false
- } else {
- diag.help(&format!(
- "this function's return type contains a borrowed value, \
+ m
+ ));
+ } else {
+ err.help(&format!(
+ "this function's return type contains a borrowed value, \
but the signature does not say whether it is borrowed from {}",
- m
- ));
- false
+ m
+ ));
+ }
}
- }
- pub(crate) fn is_trait_ref_fn_scope(
- &mut self,
- trait_ref: &'tcx hir::PolyTraitRef<'tcx>,
- ) -> bool {
- if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
- if [
- self.tcx.lang_items().fn_once_trait(),
- self.tcx.lang_items().fn_trait(),
- self.tcx.lang_items().fn_mut_trait(),
- ]
- .contains(&Some(did))
- {
- let (span, span_type) = if let Some(bound) =
- trait_ref.bound_generic_params.iter().rfind(|param| {
- matches!(
- param.kind,
- hir::GenericParamKind::Lifetime {
- kind: hir::LifetimeParamKind::Explicit
- }
- )
- }) {
- (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail)
- } else {
- (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty)
- };
- self.missing_named_lifetime_spots
- .push(MissingLifetimeSpot::HigherRanked { span, span_type });
- return true;
- }
+ let existing_name = match &in_scope_lifetimes[..] {
+ [] => Symbol::intern("'a"),
+ [(existing, _)] => existing.name,
+ _ => Symbol::intern("'lifetime"),
};
- false
- }
-
- pub(crate) fn add_missing_lifetime_specifiers_label(
- &self,
- err: &mut Diagnostic,
- mut spans_with_counts: Vec<(Span, usize)>,
- in_scope_lifetimes: FxIndexSet<LocalDefId>,
- params: Option<&[ElisionFailureInfo]>,
- ) {
- let (mut lifetime_names, lifetime_spans): (FxHashSet<_>, Vec<_>) = in_scope_lifetimes
- .iter()
- .filter_map(|def_id| {
- let name = self.tcx.item_name(def_id.to_def_id());
- let span = self.tcx.def_ident_span(def_id.to_def_id())?;
- Some((name, span))
- })
- .filter(|&(n, _)| n != kw::UnderscoreLifetime)
- .unzip();
- if let Some(params) = params {
- // If there's no lifetime available, suggest `'static`.
- if self.report_elision_failure(err, params) && lifetime_names.is_empty() {
- lifetime_names.insert(kw::StaticLifetime);
+ let mut spans_suggs: Vec<_> = Vec::new();
+ let build_sugg = |lt: MissingLifetime| match lt.kind {
+ MissingLifetimeKind::Underscore => {
+ debug_assert_eq!(lt.count, 1);
+ (lt.span, existing_name.to_string())
}
- }
- let params = params.unwrap_or(&[]);
-
- let snippets: Vec<Option<String>> = spans_with_counts
- .iter()
- .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())
- .collect();
-
- // Empty generics are marked with a span of "<", but since from now on
- // that information is in the snippets it can be removed from the spans.
- for ((span, _), snippet) in spans_with_counts.iter_mut().zip(&snippets) {
- if snippet.as_deref() == Some("<") {
- *span = span.shrink_to_hi();
+ MissingLifetimeKind::Ampersand => {
+ debug_assert_eq!(lt.count, 1);
+ (lt.span.shrink_to_hi(), format!("{} ", existing_name))
}
+ MissingLifetimeKind::Comma => {
+ let sugg: String = std::iter::repeat([existing_name.as_str(), ", "])
+ .take(lt.count)
+ .flatten()
+ .collect();
+ (lt.span.shrink_to_hi(), sugg)
+ }
+ MissingLifetimeKind::Brackets => {
+ let sugg: String = std::iter::once("<")
+ .chain(
+ std::iter::repeat(existing_name.as_str()).take(lt.count).intersperse(", "),
+ )
+ .chain([">"])
+ .collect();
+ (lt.span.shrink_to_hi(), sugg)
+ }
+ };
+ for < in &lifetime_refs {
+ spans_suggs.push(build_sugg(lt));
}
-
- for &(span, count) in &spans_with_counts {
- err.span_label(
- span,
- format!(
- "expected {} lifetime parameter{}",
- if count == 1 { "named".to_string() } else { count.to_string() },
- pluralize!(count),
- ),
- );
- }
-
- let suggest_existing =
- |err: &mut Diagnostic,
- name: Symbol,
- formatters: Vec<Option<Box<dyn Fn(Symbol) -> String>>>| {
- if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) =
- self.missing_named_lifetime_spots.iter().rev().next()
- {
- // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest
- // using `'a`, but also introduce the concept of HRLTs by suggesting
- // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404)
- let mut introduce_suggestion = vec![];
-
- let a_to_z_repeat_n = |n| {
- (b'a'..=b'z').map(move |c| {
- let mut s = '\''.to_string();
- s.extend(std::iter::repeat(char::from(c)).take(n));
- s
- })
- };
-
- // If all single char lifetime names are present, we wrap around and double the chars.
- let lt_name = (1..)
- .flat_map(a_to_z_repeat_n)
- .map(|lt| Symbol::intern(<))
- .find(|lt| !lifetime_names.contains(lt))
- .unwrap();
- let msg = format!(
- "consider making the {} lifetime-generic with a new `{}` lifetime",
- span_type.descr(),
- lt_name,
- );
- err.note(
- "for more information on higher-ranked polymorphism, visit \
- https://doc.rust-lang.org/nomicon/hrtb.html",
- );
- let for_sugg = span_type.suggestion(<_name);
- for param in params {
- if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span)
- {
- if snippet.starts_with('&') && !snippet.starts_with("&'") {
- introduce_suggestion
- .push((param.span, format!("&{} {}", lt_name, &snippet[1..])));
- } else if let Some(stripped) = snippet.strip_prefix("&'_ ") {
- introduce_suggestion
- .push((param.span, format!("&{} {}", lt_name, stripped)));
- }
- }
+ debug!(?spans_suggs);
+ match in_scope_lifetimes.len() {
+ 0 => {
+ if let Some((param_lifetimes, _)) = function_param_lifetimes {
+ for lt in param_lifetimes {
+ spans_suggs.push(build_sugg(lt))
}
- introduce_suggestion.push((*for_span, for_sugg));
- for ((span, _), formatter) in spans_with_counts.iter().zip(formatters.iter()) {
- if let Some(formatter) = formatter {
- introduce_suggestion.push((*span, formatter(lt_name)));
- }
- }
- err.multipart_suggestion_verbose(
- &msg,
- introduce_suggestion,
- Applicability::MaybeIncorrect,
- );
}
-
- let spans_suggs: Vec<_> = formatters
- .into_iter()
- .zip(spans_with_counts.iter())
- .filter_map(|(formatter, (span, _))| {
- if let Some(formatter) = formatter {
- Some((*span, formatter(name)))
- } else {
- None
- }
- })
- .collect();
- if spans_suggs.is_empty() {
- // If all the spans come from macros, we cannot extract snippets and then
- // `formatters` only contains None and `spans_suggs` is empty.
- return;
- }
- err.multipart_suggestion_verbose(
- &format!(
- "consider using the `{}` lifetime",
- lifetime_names.iter().next().unwrap()
- ),
- spans_suggs,
- Applicability::MaybeIncorrect,
- );
- };
- let suggest_new = |err: &mut Diagnostic, suggs: Vec<Option<String>>| {
- for missing in self.missing_named_lifetime_spots.iter().rev() {
- let mut introduce_suggestion = vec![];
- let msg;
- let should_break;
- introduce_suggestion.push(match missing {
- MissingLifetimeSpot::Generics(generics) => {
- if generics.span == DUMMY_SP {
- // Account for malformed generics in the HIR. This shouldn't happen,
- // but if we make a mistake elsewhere, mainly by keeping something in
- // `missing_named_lifetime_spots` that we shouldn't, like associated
- // `const`s or making a mistake in the AST lowering we would provide
- // nonsensical suggestions. Guard against that by skipping these.
- // (#74264)
- continue;
- }
- msg = "consider introducing a named lifetime parameter".to_string();
- should_break = true;
- if let Some(param) = generics.params.iter().find(|p| {
- !matches!(
- p.kind,
- hir::GenericParamKind::Type { synthetic: true, .. }
- | hir::GenericParamKind::Lifetime {
- kind: hir::LifetimeParamKind::Elided
- }
- )
- }) {
- (param.span.shrink_to_lo(), "'a, ".to_string())
- } else {
- (generics.span, "<'a>".to_string())
- }
- }
- MissingLifetimeSpot::HigherRanked { span, span_type } => {
- msg = format!(
- "consider making the {} lifetime-generic with a new `'a` lifetime",
- span_type.descr(),
- );
- should_break = false;
- err.note(
- "for more information on higher-ranked polymorphism, visit \
- https://doc.rust-lang.org/nomicon/hrtb.html",
- );
- (*span, span_type.suggestion("'a"))
- }
- MissingLifetimeSpot::Static => {
- let mut spans_suggs = Vec::new();
- for ((span, count), snippet) in
- spans_with_counts.iter().copied().zip(snippets.iter())
- {
- let (span, sugg) = match snippet.as_deref() {
- Some("&") => (span.shrink_to_hi(), "'static ".to_owned()),
- Some("'_") => (span, "'static".to_owned()),
- Some(snippet) if !snippet.ends_with('>') => {
- if snippet == "" {
- (
- span,
- std::iter::repeat("'static")
- .take(count)
- .collect::<Vec<_>>()
- .join(", "),
- )
- } else if snippet == "<" || snippet == "(" {
- (
- span.shrink_to_hi(),
- std::iter::repeat("'static")
- .take(count)
- .collect::<Vec<_>>()
- .join(", "),
- )
- } else {
- (
- span.shrink_to_hi(),
- format!(
- "<{}>",
- std::iter::repeat("'static")
- .take(count)
- .collect::<Vec<_>>()
- .join(", "),
- ),
- )
- }
- }
- _ => continue,
- };
- spans_suggs.push((span, sugg.to_string()));
- }
+ self.suggest_introducing_lifetime(
+ err,
+ None,
+ |err, higher_ranked, span, message, intro_sugg| {
err.multipart_suggestion_verbose(
- "consider using the `'static` lifetime",
- spans_suggs,
+ message,
+ std::iter::once((span, intro_sugg))
+ .chain(spans_suggs.clone())
+ .collect(),
Applicability::MaybeIncorrect,
);
- continue;
- }
- });
-
- struct Lifetime(Span, String);
- impl Lifetime {
- fn is_unnamed(&self) -> bool {
- self.1.starts_with('&') && !self.1.starts_with("&'")
- }
- fn is_underscore(&self) -> bool {
- self.1.starts_with("&'_ ")
- }
- fn is_named(&self) -> bool {
- self.1.starts_with("&'")
- }
- fn suggestion(&self, sugg: String) -> Option<(Span, String)> {
- Some(
- match (
- self.is_unnamed(),
- self.is_underscore(),
- self.is_named(),
- sugg.starts_with('&'),
- ) {
- (true, _, _, false) => (self.span_unnamed_borrow(), sugg),
- (true, _, _, true) => {
- (self.span_unnamed_borrow(), sugg[1..].to_string())
- }
- (_, true, _, false) => {
- (self.span_underscore_borrow(), sugg.trim().to_string())
- }
- (_, true, _, true) => {
- (self.span_underscore_borrow(), sugg[1..].trim().to_string())
- }
- (_, _, true, false) => {
- (self.span_named_borrow(), sugg.trim().to_string())
- }
- (_, _, true, true) => {
- (self.span_named_borrow(), sugg[1..].trim().to_string())
- }
- _ => return None,
- },
- )
- }
- fn span_unnamed_borrow(&self) -> Span {
- let lo = self.0.lo() + BytePos(1);
- self.0.with_lo(lo).with_hi(lo)
- }
- fn span_named_borrow(&self) -> Span {
- let lo = self.0.lo() + BytePos(1);
- self.0.with_lo(lo)
- }
- fn span_underscore_borrow(&self) -> Span {
- let lo = self.0.lo() + BytePos(1);
- let hi = lo + BytePos(2);
- self.0.with_lo(lo).with_hi(hi)
- }
- }
-
- for param in params {
- if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
- if let Some((span, sugg)) =
- Lifetime(param.span, snippet).suggestion("'a ".to_string())
- {
- introduce_suggestion.push((span, sugg));
- }
- }
- }
- for (span, sugg) in spans_with_counts.iter().copied().zip(suggs.iter()).filter_map(
- |((span, _), sugg)| match &sugg {
- Some(sugg) => Some((span, sugg.to_string())),
- _ => None,
+ higher_ranked
},
- ) {
- let (span, sugg) = self
- .tcx
- .sess
- .source_map()
- .span_to_snippet(span)
- .ok()
- .and_then(|snippet| Lifetime(span, snippet).suggestion(sugg.clone()))
- .unwrap_or((span, sugg));
- introduce_suggestion.push((span, sugg.to_string()));
- }
+ );
+ }
+ 1 => {
err.multipart_suggestion_verbose(
- &msg,
- introduce_suggestion,
+ &format!("consider using the `{}` lifetime", existing_name),
+ spans_suggs,
Applicability::MaybeIncorrect,
);
- if should_break {
- break;
- }
- }
- };
- let lifetime_names: Vec<_> = lifetime_names.iter().collect();
- match &lifetime_names[..] {
- [name] => {
- let mut suggs: Vec<Option<Box<dyn Fn(Symbol) -> String>>> = Vec::new();
- for (snippet, (_, count)) in snippets.iter().zip(spans_with_counts.iter().copied())
- {
- suggs.push(match snippet.as_deref() {
- Some("&") => Some(Box::new(|name| format!("&{} ", name))),
- Some("'_") => Some(Box::new(|n| n.to_string())),
- Some("") => Some(Box::new(move |n| format!("{}, ", n).repeat(count))),
- Some("<") => Some(Box::new(move |n| {
- std::iter::repeat(n)
- .take(count)
- .map(|n| n.to_string())
- .collect::<Vec<_>>()
- .join(", ")
- })),
- Some(snippet) if !snippet.ends_with('>') => Some(Box::new(move |name| {
- format!(
- "{}<{}>",
- snippet,
- std::iter::repeat(name.to_string())
- .take(count)
- .collect::<Vec<_>>()
- .join(", ")
- )
- })),
- _ => None,
- });
+ // Record as using the suggested resolution.
+ let (_, (_, res)) = in_scope_lifetimes[0];
+ for < in &lifetime_refs {
+ self.r.lifetimes_res_map.insert(lt.id, res);
}
- suggest_existing(err, **name, suggs);
}
- [] => {
- let mut suggs = Vec::new();
- for (snippet, (_, count)) in
- snippets.iter().cloned().zip(spans_with_counts.iter().copied())
- {
- suggs.push(match snippet.as_deref() {
- Some("&") => Some("&'a ".to_string()),
- Some("'_") => Some("'a".to_string()),
- Some("") => {
- Some(std::iter::repeat("'a, ").take(count).collect::<Vec<_>>().join(""))
- }
- Some("<") => {
- Some(std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "))
- }
- Some(snippet) => Some(format!(
- "{}<{}>",
- snippet,
- std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "),
- )),
- None => None,
- });
- }
- suggest_new(err, suggs);
- }
- lts if lts.len() > 1 => {
+ _ => {
+ let lifetime_spans: Vec<_> =
+ in_scope_lifetimes.iter().map(|(ident, _)| ident.span).collect();
err.span_note(lifetime_spans, "these named lifetimes are available to use");
- let mut spans_suggs: Vec<_> = Vec::new();
- for ((span, _), snippet) in spans_with_counts.iter().copied().zip(snippets.iter()) {
- match snippet.as_deref() {
- Some("") => spans_suggs.push((span, "'lifetime, ".to_string())),
- Some("&") => spans_suggs
- .push((span.with_lo(span.lo() + BytePos(1)), "'lifetime ".to_string())),
- _ => {}
- }
- }
-
if spans_suggs.len() > 0 {
// This happens when we have `Foo<T>` where we point at the space before `T`,
// but this can be confusing so we give a suggestion with placeholders.
);
}
}
- _ => unreachable!(),
}
}
}
+
+/// Report lifetime/lifetime shadowing as an error.
+pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
+ let mut err = struct_span_err!(
+ sess,
+ shadower.span,
+ E0496,
+ "lifetime name `{}` shadows a lifetime name that is already in scope",
+ orig.name,
+ );
+ err.span_label(orig.span, "first declared here");
+ err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name));
+ err.emit();
+}
+
+/// Shadowing involving a label is only a warning for historical reasons.
+//FIXME: make this a proper lint.
+pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
+ let name = shadower.name;
+ let shadower = shadower.span;
+ let mut err = sess.struct_span_warn(
+ shadower,
+ &format!("label name `{}` shadows a label name that is already in scope", name),
+ );
+ err.span_label(orig, "first declared here");
+ err.span_label(shadower, format!("label `{}` already in scope", name));
+ err.emit();
+}
// ignore-tidy-filelength
-//! Name resolution for lifetimes.
+//! Resolution of early vs late bound lifetimes.
//!
-//! Name resolution for lifetimes follows *much* simpler rules than the
-//! full resolve. For example, lifetime names are never exported or
-//! used between functions, and they operate in a purely top-down
-//! way. Therefore, we break lifetime name resolution into a separate pass.
+//! Name resolution for lifetimes is performed on the AST and embedded into HIR. From this
+//! information, typechecking needs to transform the lifetime parameters into bound lifetimes.
+//! Lifetimes can be early-bound or late-bound. Construction of typechecking terms needs to visit
+//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file
+//! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
-use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
use rustc_ast::walk_list;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::struct_span_err;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefIdMap, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
-use rustc_hir::{GenericParamKind, HirIdMap, LifetimeParamKind};
+use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
+use rustc_middle::bug;
use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::*;
use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
-use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
/// Cache for cross-crate per-definition object lifetime defaults.
xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
-
- /// When encountering an undefined named lifetime, we will suggest introducing it in these
- /// places.
- pub(crate) missing_named_lifetime_spots: Vec<MissingLifetimeSpot<'tcx>>,
}
#[derive(Debug)]
/// Always use this one lifetime.
Exact(Region),
/// Less or more than one lifetime were found, error on unspecified.
- Error(Vec<ElisionFailureInfo>),
+ Error,
/// Forbid lifetime elision inside of a larger scope where it would be
/// permitted. For example, in let position impl trait.
Forbid,
}
-#[derive(Clone, Debug)]
-pub(crate) struct ElisionFailureInfo {
- /// Where we can find the argument pattern.
- pub(crate) parent: Option<hir::BodyId>,
- /// The index of the argument in the original definition.
- pub(crate) index: usize,
- pub(crate) lifetime_count: usize,
- pub(crate) have_bound_regions: bool,
- pub(crate) span: Span,
-}
-
type ScopeRef<'a> = &'a Scope<'a>;
const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
scope: ROOT_SCOPE,
trait_definition_only,
xcrate_object_lifetime_defaults: Default::default(),
- missing_named_lifetime_spots: vec![],
};
visitor.visit_item(item);
where_bound_origin: None,
};
- if let &hir::ClosureBinder::For { span, .. } = binder {
- let last_lt = bound_generic_params
- .iter()
- .filter(|p| {
- matches!(
- p,
- GenericParam {
- kind: GenericParamKind::Lifetime {
- kind: LifetimeParamKind::Explicit
- },
- ..
- }
- )
- })
- .last();
- let (span, span_type) = match last_lt {
- Some(GenericParam { span: last_sp, .. }) => {
- (last_sp.shrink_to_hi(), ForLifetimeSpanType::ClosureTail)
- }
- None => (span, ForLifetimeSpanType::ClosureEmpty),
- };
- self.missing_named_lifetime_spots
- .push(MissingLifetimeSpot::HigherRanked { span, span_type });
- }
-
self.with(scope, |this| {
// a closure has no bounds, so everything
// contained within is scoped within its binder.
intravisit::walk_expr(this, e)
});
-
- if let hir::ClosureBinder::For { .. } = binder {
- self.missing_named_lifetime_spots.pop();
- }
} else {
intravisit::walk_expr(self, e)
}
}
match item.kind {
hir::ItemKind::Fn(_, ref generics, _) => {
- self.missing_named_lifetime_spots.push(generics.into());
self.visit_early_late(None, item.hir_id(), generics, |this| {
intravisit::walk_item(this, item);
});
- self.missing_named_lifetime_spots.pop();
}
hir::ItemKind::ExternCrate(_)
| hir::ItemKind::Trait(_, _, ref generics, ..)
| hir::ItemKind::TraitAlias(ref generics, ..)
| hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
- self.missing_named_lifetime_spots.push(generics.into());
-
// These kinds of items have only early-bound lifetime parameters.
let mut index = if sub_items_have_self_param(&item.kind) {
1 // Self comes before lifetimes
intravisit::walk_item(this, item);
});
});
- self.missing_named_lifetime_spots.pop();
}
}
}
match ty.kind {
hir::TyKind::BareFn(ref c) => {
let next_early_index = self.next_early_index();
- let lifetime_span: Option<Span> =
- c.generic_params.iter().rev().find_map(|param| match param.kind {
- GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => {
- Some(param.span)
- }
- _ => None,
- });
- let (span, span_type) = if let Some(span) = lifetime_span {
- (span.shrink_to_hi(), ForLifetimeSpanType::TypeTail)
- } else {
- (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty)
- };
- self.missing_named_lifetime_spots
- .push(MissingLifetimeSpot::HigherRanked { span, span_type });
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
.generic_params
.iter()
// contained within is scoped within its binder.
intravisit::walk_ty(this, ty);
});
- self.missing_named_lifetime_spots.pop();
}
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
debug!(?bounds, ?lifetime, "TraitObject");
}
});
match lifetime.name {
- LifetimeName::Implicit => {
- // For types like `dyn Foo`, we should
- // generate a special form of elided.
- span_bug!(ty.span, "object-lifetime-default expected, not implicit",);
- }
LifetimeName::ImplicitObjectLifetimeDefault => {
// If the user does not write *anything*, we
// use the object lifetime defaulting
// `Box<dyn Debug + 'static>`.
self.resolve_object_lifetime_default(lifetime)
}
- LifetimeName::Underscore => {
+ LifetimeName::Implicit | LifetimeName::Underscore => {
// If the user writes `'_`, we use the *ordinary* elision
// rules. So the `'_` in e.g., `Box<dyn Debug + '_>` will be
// resolved the same as the `'_` in `&'_ Foo`.
let mut elision = None;
let mut lifetimes = FxIndexMap::default();
let mut non_lifetime_count = 0;
+ debug!(?generics.params);
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {
let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, ¶m);
+ lifetimes.insert(def_id, reg);
if let hir::ParamName::Plain(Ident {
name: kw::UnderscoreLifetime,
..
// Pick the elided lifetime "definition" if one exists
// and use it to make an elision scope.
elision = Some(reg);
- } else {
- lifetimes.insert(def_id, reg);
}
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
use self::hir::TraitItemKind::*;
match trait_item.kind {
Fn(_, _) => {
- self.missing_named_lifetime_spots.push((&trait_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
Some(tcx.hir().get_parent_item(trait_item.hir_id())),
&trait_item.generics,
|this| intravisit::walk_trait_item(this, trait_item),
);
- self.missing_named_lifetime_spots.pop();
}
Type(bounds, ref ty) => {
- self.missing_named_lifetime_spots.push((&trait_item.generics).into());
let generics = &trait_item.generics;
let mut index = self.next_early_index();
debug!("visit_ty: index = {}", index);
}
})
});
- self.missing_named_lifetime_spots.pop();
}
Const(_, _) => {
// Only methods and types support generics.
assert!(trait_item.generics.params.is_empty());
- self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
intravisit::walk_trait_item(self, trait_item);
- self.missing_named_lifetime_spots.pop();
}
}
}
use self::hir::ImplItemKind::*;
match impl_item.kind {
Fn(..) => {
- self.missing_named_lifetime_spots.push((&impl_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
Some(tcx.hir().get_parent_item(impl_item.hir_id())),
&impl_item.generics,
|this| intravisit::walk_impl_item(this, impl_item),
);
- self.missing_named_lifetime_spots.pop();
}
TyAlias(ref ty) => {
let generics = &impl_item.generics;
- self.missing_named_lifetime_spots.push(generics.into());
let mut index = self.next_early_index();
let mut non_lifetime_count = 0;
debug!("visit_ty: index = {}", index);
this.visit_ty(ty);
})
});
- self.missing_named_lifetime_spots.pop();
}
Const(_, _) => {
// Only methods and types support generics.
assert!(impl_item.generics.params.is_empty());
- self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
intravisit::walk_impl_item(self, impl_item);
- self.missing_named_lifetime_spots.pop();
}
}
}
) {
debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
- let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref);
-
let next_early_index = self.next_early_index();
let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
this.visit_trait_ref(&trait_ref.trait_ref);
});
-
- if should_pop_missing_lt {
- self.missing_named_lifetime_spots.pop();
- }
}
}
{
let LifetimeContext { tcx, map, .. } = self;
let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
- let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots);
let mut this = LifetimeContext {
tcx: *tcx,
map,
scope: &wrap_scope,
trait_definition_only: self.trait_definition_only,
xcrate_object_lifetime_defaults,
- missing_named_lifetime_spots,
};
let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
{
f(&mut this);
}
self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
- self.missing_named_lifetime_spots = this.missing_named_lifetime_spots;
}
/// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
let mut assoc_item_kind = None;
let mut impl_self = None;
let parent = self.tcx.hir().get_parent_node(output.hir_id);
- let body = match self.tcx.hir().get(parent) {
+ match self.tcx.hir().get(parent) {
// `fn` definitions and methods.
- Node::Item(&hir::Item { kind: hir::ItemKind::Fn(.., body), .. }) => Some(body),
+ Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) => {}
- Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(_, ref m), .. }) => {
+ Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => {
if let hir::ItemKind::Trait(.., ref trait_items) =
self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
{
assoc_item_kind =
trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind);
}
- match *m {
- hir::TraitFn::Required(_) => None,
- hir::TraitFn::Provided(body) => Some(body),
- }
}
- Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => {
+ Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, _), .. }) => {
if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) =
self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
{
assoc_item_kind =
items.iter().find(|ii| ii.id.hir_id() == parent).map(|ii| ii.kind);
}
- Some(body)
}
// Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
- Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None,
+ Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => {},
- Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => None,
+ Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => {},
// Everything else (only closures?) doesn't
// actually enjoy elision in return types.
// have that lifetime.
let mut possible_implied_output_region = None;
let mut lifetime_count = 0;
- let arg_lifetimes = inputs
- .iter()
- .enumerate()
- .skip(has_self as usize)
- .map(|(i, input)| {
- let mut gather = GatherLifetimes {
- map: self.map,
- outer_index: ty::INNERMOST,
- have_bound_regions: false,
- lifetimes: Default::default(),
- };
- gather.visit_ty(input);
-
- lifetime_count += gather.lifetimes.len();
+ for input in inputs.iter().skip(has_self as usize) {
+ let mut gather = GatherLifetimes {
+ map: self.map,
+ outer_index: ty::INNERMOST,
+ have_bound_regions: false,
+ lifetimes: Default::default(),
+ };
+ gather.visit_ty(input);
- if lifetime_count == 1 && gather.lifetimes.len() == 1 {
- // there's a chance that the unique lifetime of this
- // iteration will be the appropriate lifetime for output
- // parameters, so lets store it.
- possible_implied_output_region = gather.lifetimes.iter().cloned().next();
- }
+ lifetime_count += gather.lifetimes.len();
- ElisionFailureInfo {
- parent: body,
- index: i,
- lifetime_count: gather.lifetimes.len(),
- have_bound_regions: gather.have_bound_regions,
- span: input.span,
- }
- })
- .collect();
+ if lifetime_count == 1 && gather.lifetimes.len() == 1 {
+ // there's a chance that the unique lifetime of this
+ // iteration will be the appropriate lifetime for output
+ // parameters, so lets store it.
+ possible_implied_output_region = gather.lifetimes.iter().cloned().next();
+ }
+ }
let elide = if lifetime_count == 1 {
Elide::Exact(possible_implied_output_region.unwrap())
} else {
- Elide::Error(arg_lifetimes)
+ Elide::Error
};
debug!(?elide);
let mut late_depth = 0;
let mut scope = self.scope;
- let mut in_scope_lifetimes = FxIndexSet::default();
- let error = loop {
+ loop {
match *scope {
// Do not assign any resolution, it will be inferred.
Scope::Body { .. } => return,
- Scope::Root => break None,
+ Scope::Root => break,
- Scope::Binder { s, ref lifetimes, scope_type, .. } => {
- // collect named lifetimes for suggestions
- in_scope_lifetimes.extend(lifetimes.keys().copied());
+ Scope::Binder { s, scope_type, .. } => {
match scope_type {
BinderScopeType::Normal => late_depth += 1,
BinderScopeType::Concatenating => {}
return;
}
- Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => {
- let mut scope = s;
- loop {
- match scope {
- Scope::Binder { ref lifetimes, s, .. } => {
- // Collect named lifetimes for suggestions.
- in_scope_lifetimes.extend(lifetimes.keys().copied());
- scope = s;
- }
- Scope::ObjectLifetimeDefault { ref s, .. }
- | Scope::Elision { ref s, .. }
- | Scope::TraitRefBoundary { ref s, .. } => {
- scope = s;
- }
- _ => break,
- }
- }
- break Some(&e[..]);
- }
-
- Scope::Elision { elide: Elide::Forbid, .. } => break None,
+ Scope::Elision { elide: Elide::Error, .. }
+ | Scope::Elision { elide: Elide::Forbid, .. } => break,
Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
scope = s;
}
}
- };
-
- let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
- spans.sort();
- let mut spans_dedup = spans.clone();
- spans_dedup.dedup();
- let spans_with_counts: Vec<_> = spans_dedup
- .into_iter()
- .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count()))
- .collect();
-
- let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len());
+ }
- self.add_missing_lifetime_specifiers_label(
- &mut err,
- spans_with_counts,
- in_scope_lifetimes,
- error,
- );
- err.emit();
+ for lt in lifetime_refs {
+ self.tcx.sess.delay_span_bug(lt.span, "Missing lifetime specifier");
+ }
}
fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
#![feature(drain_filter)]
#![feature(if_let_guard)]
#![cfg_attr(bootstrap, feature(let_chains))]
+#![feature(iter_intersperse)]
#![feature(let_else)]
#![feature(never_type)]
#![recursion_limit = "256"]
/// f(); // Resolves to (1)
/// }
/// ```
- Block(NodeId),
+ Block,
/// Any module with a name.
///
/// This could be:
/// Get name of the module.
pub fn name(&self) -> Option<Symbol> {
match self {
- ModuleKind::Block(..) => None,
+ ModuleKind::Block => None,
ModuleKind::Def(.., name) => Some(*name),
}
}
) -> Self {
let is_foreign = match kind {
ModuleKind::Def(_, def_id, _) => !def_id.is_local(),
- ModuleKind::Block(_) => false,
+ ModuleKind::Block => false,
};
ModuleData {
parent,
stability::report_unstable(
self.session,
feature,
- reason,
+ reason.to_opt_reason(),
issue,
None,
is_soft,
"emit a section containing stack size metadata (default: no)"),
emit_thin_lto: bool = (true, parse_bool, [TRACKED],
"emit the bc module with thin LTO info (default: yes)"),
+ export_executable_symbols: bool = (false, parse_bool, [TRACKED],
+ "export symbols from executables, as if they were dynamic libraries"),
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
(default: no)"),
}
}
- /// Returns whether or not this span points into a file
- /// in the current crate. This may be `false` for spans
- /// produced by a macro expansion, or for spans associated
- /// with the definition of an item in a foreign crate
- pub fn is_local_span(&self, sp: Span) -> bool {
- let local_begin = self.lookup_byte_offset(sp.lo());
- let local_end = self.lookup_byte_offset(sp.hi());
- // This might be a weird span that covers multiple files
- local_begin.sf.src.is_some() && local_end.sf.src.is_some()
- }
-
pub fn is_span_accessible(&self, sp: Span) -> bool {
self.span_to_source(sp, |src, start_index, end_index| {
Ok(src.get(start_index..end_index).is_some())
rustc,
rustc_allocator,
rustc_allocator_nounwind,
+ rustc_allocator_zeroed,
rustc_allow_const_fn_unstable,
rustc_allow_incoherent_impl,
rustc_allowed_through_unstable_modules,
rustc_const_stable,
rustc_const_unstable,
rustc_conversion_suggestion,
+ rustc_deallocator,
rustc_def_path,
rustc_diagnostic_item,
rustc_diagnostic_macros,
rustc_private,
rustc_proc_macro_decls,
rustc_promotable,
+ rustc_reallocator,
rustc_regions,
rustc_reservation_impl,
rustc_serialize,
unsized_locals,
unsized_tuple_coercion,
unstable,
+ unstable_location_reason_default: "this crate is being loaded from the sysroot, an \
+ unstable location; did you mean to load this crate \
+ from crates.io via `Cargo.toml` instead?",
untagged_unions,
unused_imports,
unused_qualifications,
}
}
ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
- ty::Opaque(..) | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
+ ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
self.tcx.sess.delay_span_bug(
DUMMY_SP,
format!("ty_is_local invoked on closure or generator: {:?}", ty),
);
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
}
+ ty::Opaque(..) => {
+ // This merits some explanation.
+ // Normally, opaque types are not involved when performing
+ // coherence checking, since it is illegal to directly
+ // implement a trait on an opaque type. However, we might
+ // end up looking at an opaque type during coherence checking
+ // if an opaque type gets used within another type (e.g. as
+ // the type of a field) when checking for auto trait or `Sized`
+ // impls. This requires us to decide whether or not an opaque
+ // type should be considered 'local' or not.
+ //
+ // We choose to treat all opaque types as non-local, even
+ // those that appear within the same crate. This seems
+ // somewhat surprising at first, but makes sense when
+ // you consider that opaque types are supposed to hide
+ // the underlying type *within the same crate*. When an
+ // opaque type is used from outside the module
+ // where it is declared, it should be impossible to observe
+ // anything about it other than the traits that it implements.
+ //
+ // The alternative would be to look at the underlying type
+ // to determine whether or not the opaque type itself should
+ // be considered local. However, this could make it a breaking change
+ // to switch the underlying ('defining') type from a local type
+ // to a remote type. This would violate the rule that opaque
+ // types should be completely opaque apart from the traits
+ // that they implement, so we don't use this behavior.
+ self.found_non_local_ty(ty)
+ }
};
// A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so
// the first type we visit is always the self type.
}
let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
match concrete {
- Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
- NotConstEvaluatable::MentionsInfer
- } else if uv.has_param_types_or_consts() {
- infcx
- .tcx
- .sess
- .delay_span_bug(span, &format!("unexpected `TooGeneric` for {:?}", uv));
- NotConstEvaluatable::MentionsParam
- } else {
- let guar = infcx.tcx.sess.delay_span_bug(
+ Err(ErrorHandled::TooGeneric) => {
+ Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
span,
format!("Missing value for constant, but no error reported?"),
- );
- NotConstEvaluatable::Error(guar)
- }),
+ )))
+ }
Err(ErrorHandled::Linted) => {
let reported = infcx
.tcx
span = obligation.cause.span;
}
}
- if let ObligationCauseCode::CompareImplMethodObligation {
- impl_item_def_id,
- trait_item_def_id,
- }
- | ObligationCauseCode::CompareImplTypeObligation {
+ if let ObligationCauseCode::CompareImplItemObligation {
impl_item_def_id,
trait_item_def_id,
+ kind: _,
} = *obligation.cause.code()
{
self.report_extra_impl_obligation(
&format!(
"expected a closure taking {} argument{}, but one taking {} argument{} was given",
given.len(),
- if given.len() == 1 { "" } else { "s" },
+ pluralize!(given.len()),
expected.len(),
- if expected.len() == 1 { "" } else { "s" },
+ pluralize!(expected.len()),
)
);
} else if !self.same_type_modulo_infer(given_ty, expected_ty) {
);
} else if !suggested {
// Can't show anything else useful, try to find similar impls.
- let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+ let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
if !self.report_similar_impl_candidates(
impl_candidates,
trait_ref,
{
let trait_ref = trait_pred.to_poly_trait_ref();
let impl_candidates =
- self.find_similar_impl_candidates(trait_ref);
+ self.find_similar_impl_candidates(trait_pred);
self.report_similar_impl_candidates(
impl_candidates,
trait_ref,
fn find_similar_impl_candidates(
&self,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Vec<ImplCandidate<'tcx>>;
fn report_similar_impl_candidates(
fn find_similar_impl_candidates(
&self,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Vec<ImplCandidate<'tcx>> {
self.tcx
- .all_impls(trait_ref.def_id())
+ .all_impls(trait_pred.def_id())
.filter_map(|def_id| {
- if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative {
+ if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative
+ || !trait_pred
+ .skip_binder()
+ .is_constness_satisfied_by(self.tcx.constness(def_id))
+ {
return None;
}
let imp = self.tcx.impl_trait_ref(def_id).unwrap();
- self.fuzzy_match_tys(trait_ref.skip_binder().self_ty(), imp.self_ty(), false)
+ self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
.map(|similarity| ImplCandidate { trait_ref: imp, similarity })
})
.collect()
)
});
}
- ObligationCauseCode::CompareImplMethodObligation { trait_item_def_id, .. } => {
+ ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => {
let item_name = self.tcx.item_name(trait_item_def_id);
let msg = format!(
- "the requirement `{}` appears on the impl method `{}` but not on the \
- corresponding trait method",
+ "the requirement `{}` appears on the `impl`'s {kind} `{}` but not on the \
+ corresponding trait's {kind}",
predicate, item_name,
);
let sp = self
let mut assoc_span: MultiSpan = sp.into();
assoc_span.push_span_label(
sp,
- format!("this trait method doesn't have the requirement `{}`", predicate),
+ format!("this trait's {kind} doesn't have the requirement `{}`", predicate),
);
if let Some(ident) = self
.tcx
}
err.span_note(assoc_span, &msg);
}
- ObligationCauseCode::CompareImplTypeObligation { trait_item_def_id, .. } => {
- let item_name = self.tcx.item_name(trait_item_def_id);
- let msg = format!(
- "the requirement `{}` appears on the associated impl type `{}` but not on the \
- corresponding associated trait type",
- predicate, item_name,
- );
- let sp = self.tcx.def_span(trait_item_def_id);
- let mut assoc_span: MultiSpan = sp.into();
- assoc_span.push_span_label(
- sp,
- format!(
- "this trait associated type doesn't have the requirement `{}`",
- predicate,
- ),
- );
- if let Some(ident) = self
- .tcx
- .opt_associated_item(trait_item_def_id)
- .and_then(|i| self.tcx.opt_item_ident(i.container.id()))
- {
- assoc_span.push_span_label(ident.span, "in this trait");
- }
- err.span_note(assoc_span, &msg);
- }
- ObligationCauseCode::CompareImplConstObligation => {
- err.note(&format!(
- "the requirement `{}` appears on the associated impl constant \
- but not on the corresponding associated trait constant",
- predicate
- ));
- }
ObligationCauseCode::TrivialBound => {
err.help("see issue #48214");
if tcx.sess.opts.unstable_features.is_nightly_build() {
/// for<'a> fn(for<'b> fn(&'a x))
///
/// you would need to shift the index for `'a` into a new binder.
+ #[inline]
#[must_use]
pub fn shifted_in(self, amount: u32) -> DebruijnIndex {
DebruijnIndex::from_u32(self.as_u32() + amount)
/// Update this index in place by shifting it "in" through
/// `amount` number of binders.
+ #[inline]
pub fn shift_in(&mut self, amount: u32) {
*self = self.shifted_in(amount);
}
/// Returns the resulting index when this value is moved out from
/// `amount` number of new binders.
+ #[inline]
#[must_use]
pub fn shifted_out(self, amount: u32) -> DebruijnIndex {
DebruijnIndex::from_u32(self.as_u32() - amount)
}
/// Update in place by shifting out from `amount` binders.
+ #[inline]
pub fn shift_out(&mut self, amount: u32) {
*self = self.shifted_out(amount);
}
/// If we invoke `shift_out_to_binder` and the region is in fact
/// bound by one of the binders we are shifting out of, that is an
/// error (and should fail an assertion failure).
+ #[inline]
pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self {
self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32())
}
use rustc_session::parse::feature_err;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{sym, Ident};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{Span, Symbol, DUMMY_SP};
use std::collections::BTreeSet;
/// the type parameter's name as a placeholder.
pub(crate) fn complain_about_missing_type_params(
&self,
- missing_type_params: Vec<String>,
+ missing_type_params: Vec<Symbol>,
def_id: DefId,
span: Span,
empty_generic_args: bool,
def_id: DefId,
generic_args: &'a GenericArgs<'a>,
span: Span,
- missing_type_params: Vec<String>,
+ missing_type_params: Vec<Symbol>,
inferred_params: Vec<Span>,
infer_args: bool,
is_object: bool,
// defaults. This will lead to an ICE if we are not
// careful!
if self.default_needs_object_self(param) {
- self.missing_type_params.push(param.name.to_string());
+ self.missing_type_params.push(param.name);
tcx.ty_error().into()
} else {
// This is a default type parameter.
.expect("missing associated type");
if !assoc_item.vis.is_accessible_from(def_scope, tcx) {
- let kind = match assoc_item.kind {
- ty::AssocKind::Type => "type",
- ty::AssocKind::Const => "const",
- _ => unreachable!(),
- };
tcx.sess
.struct_span_err(
binding.span,
- &format!("associated {kind} `{}` is private", binding.item_name),
+ &format!("{} `{}` is private", assoc_item.kind, binding.item_name),
)
- .span_label(binding.span, &format!("private associated {kind}"))
+ .span_label(binding.span, &format!("private {}", assoc_item.kind))
.emit();
}
tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref: ty::TraitRef {
def_id: t.def_id(),
- substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
+ substs: self.tcx.mk_substs_trait(outer_ty, &[]),
},
constness: t.constness,
polarity: t.polarity,
let obl = Obligation::new(
o.cause.clone(),
self.param_env,
- pred.to_predicate(self.infcx.tcx),
+ pred.to_predicate(self.tcx),
);
- suggest_box &= self.infcx.predicate_must_hold_modulo_regions(&obl);
+ suggest_box &= self.predicate_must_hold_modulo_regions(&obl);
if !suggest_box {
// We've encountered some obligation that didn't hold, so the
// return expression can't just be boxed. We don't need to
self.param_env,
*predicate,
);
- let result = self.infcx.evaluate_obligation(&obligation);
+ let result = self.evaluate_obligation(&obligation);
self.tcx
.sess
.struct_span_err(
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
);
- let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
+ let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: self.tcx.hir().span(expr.hir_id),
});
// Create a type variable (for now) to represent the closure kind.
// It will be unified during the upvar inference phase (`upvar.rs`)
- None => self.infcx.next_ty_var(TypeVariableOrigin {
+ None => self.next_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr.span,
//
// [c1]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341089706
// [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796
- self.infcx.commit_if_ok(|_| {
+ self.commit_if_ok(|_| {
let mut all_obligations = vec![];
// The liberated version of this signature should be a subtype
expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'.
) {
// Instantiate (this part of..) S to S', i.e., with fresh variables.
- let supplied_ty = self.infcx.replace_bound_vars_with_fresh_vars(
+ let supplied_ty = self.replace_bound_vars_with_fresh_vars(
hir_ty.span,
LateBoundRegionConversionTime::FnCall,
supplied_sig.inputs().rebind(supplied_ty),
all_obligations.extend(obligations);
}
- let supplied_output_ty = self.infcx.replace_bound_vars_with_fresh_vars(
+ let supplied_output_ty = self.replace_bound_vars_with_fresh_vars(
decl.output.span(),
LateBoundRegionConversionTime::FnCall,
supplied_sig.output(),
make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
) -> CoerceResult<'tcx> {
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
- assert!(a.is_ty_var() && self.infcx.shallow_resolve(a) == a);
- assert!(self.infcx.shallow_resolve(b) == b);
+ assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
+ assert!(self.shallow_resolve(b) == b);
if b.is_ty_var() {
// Two unresolved type variables: create a `Coerce` predicate.
let target_ty = if self.use_lub {
- self.infcx.next_ty_var(TypeVariableOrigin {
+ self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::LatticeVariable,
span: self.cause.span,
})
self.autoderef(rustc_span::DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| {
self.infcx
.type_implements_trait(
- self.infcx.tcx.lang_items().deref_mut_trait()?,
+ self.tcx.lang_items().deref_mut_trait()?,
expr_ty,
ty::List::empty(),
self.param_env,
let mut cause = ObligationCause::new(
impl_m_span,
impl_m_hir_id,
- ObligationCauseCode::CompareImplMethodObligation {
+ ObligationCauseCode::CompareImplItemObligation {
impl_item_def_id: impl_m.def_id.expect_local(),
trait_item_def_id: trait_m.def_id,
+ kind: impl_m.kind,
},
);
let cause = ObligationCause::new(
span,
impl_m_hir_id,
- ObligationCauseCode::CompareImplMethodObligation {
+ ObligationCauseCode::CompareImplItemObligation {
impl_item_def_id: impl_m.def_id.expect_local(),
trait_item_def_id: trait_m.def_id,
+ kind: impl_m.kind,
},
);
ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
let mut cause = ObligationCause::new(
impl_c_span,
impl_c_hir_id,
- ObligationCauseCode::CompareImplConstObligation,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_c.def_id.expect_local(),
+ trait_item_def_id: trait_c.def_id,
+ kind: impl_c.kind,
+ },
);
// There is no "body" here, so just pass dummy id.
// `ObligationCause` (and the `FnCtxt`). This is what
// `regionck_item` expects.
let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
- let cause = ObligationCause::new(
- impl_ty_span,
- impl_ty_hir_id,
- ObligationCauseCode::CompareImplTypeObligation {
- impl_item_def_id: impl_ty.def_id.expect_local(),
- trait_item_def_id: trait_ty.def_id,
- },
- );
-
debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs);
// The predicates declared by the impl definition, the trait and the
Reveal::UserFacing,
hir::Constness::NotConst,
);
- let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause.clone());
+ let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
tcx.infer_ctxt().enter(|infcx| {
let ocx = ObligationCtxt::new(&infcx);
let mut selcx = traits::SelectionContext::new(&infcx);
- for predicate in impl_ty_own_bounds.predicates {
+ assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
+ for (span, predicate) in
+ std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
+ {
+ let cause = ObligationCause::misc(span, impl_ty_hir_id);
let traits::Normalized { value: predicate, obligations } =
- traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
+ traits::normalize(&mut selcx, param_env, cause, predicate);
+ let cause = ObligationCause::new(
+ span,
+ impl_ty_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_ty.def_id.expect_local(),
+ trait_item_def_id: trait_ty.def_id,
+ kind: impl_ty.kind,
+ },
+ );
ocx.register_obligations(obligations);
- ocx.register_obligation(traits::Obligation::new(cause.clone(), param_env, predicate));
+ ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
}
// Check that all obligations are satisfied by the implementation's
expr_ty: Ty<'tcx>,
) {
if let ty::Adt(expected_adt, substs) = expected.kind() {
+ if let hir::ExprKind::Field(base, ident) = expr.kind {
+ let base_ty = self.typeck_results.borrow().expr_ty(base);
+ if self.can_eq(self.param_env, base_ty, expected).is_ok()
+ && let Some(base_span) = base.span.find_ancestor_inside(expr.span)
+ {
+ err.span_suggestion_verbose(
+ expr.span.with_lo(base_span.hi()),
+ format!("consider removing the tuple struct field `{ident}`"),
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ return
+ }
+ }
+
// If the expression is of type () and it's the return expression of a block,
// we suggest adding a separate return expression instead.
// (To avoid things like suggesting `Ok(while .. { .. })`.)
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
_,
&ty::Ref(_, checked, _),
- ) if self.infcx.can_sub(self.param_env, checked, expected).is_ok() => {
+ ) if self.can_sub(self.param_env, checked, expected).is_ok() => {
// We have `&T`, check if what was expected was `T`. If so,
// we may want to suggest removing a `&`.
if sm.is_imported(expr.span) {
// For this suggestion to make sense, the type would need to be `Copy`,
// or we have to be moving out of a `Box<T>`
- if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp)
+ if self.type_is_copy_modulo_regions(self.param_env, expected, sp)
// FIXME(compiler-errors): We can actually do this if the checked_ty is
// `steps` layers of boxes, not just one, but this is easier and most likely.
|| (checked_ty.is_box() && steps == 1)
base: &'tcx hir::Expr<'tcx>,
ty: Ty<'tcx>,
) {
- let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
+ let output_ty = match self.get_impl_future_output_ty(ty) {
Some(output_ty) => self.resolve_vars_if_possible(output_ty),
_ => return,
};
.diverging_type_vars
.borrow()
.iter()
- .map(|&ty| self.infcx.shallow_resolve(ty))
+ .map(|&ty| self.shallow_resolve(ty))
.filter_map(|ty| ty.ty_vid())
- .map(|vid| self.infcx.root_var(vid))
+ .map(|vid| self.root_var(vid))
.collect();
debug!(
"calculate_diverging_fallback: diverging_type_vars={:?}",
let mut diverging_vids = vec![];
let mut non_diverging_vids = vec![];
for unsolved_vid in unsolved_vids {
- let root_vid = self.infcx.root_var(unsolved_vid);
+ let root_vid = self.root_var(unsolved_vid);
debug!(
"calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}",
unsolved_vid,
// variables. (Note that this set consists of "root variables".)
let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph);
for &non_diverging_vid in &non_diverging_vids {
- let root_vid = self.infcx.root_var(non_diverging_vid);
+ let root_vid = self.root_var(non_diverging_vid);
if roots_reachable_from_diverging.visited(root_vid) {
continue;
}
diverging_fallback.reserve(diverging_vids.len());
for &diverging_vid in &diverging_vids {
let diverging_ty = self.tcx.mk_ty_var(diverging_vid);
- let root_vid = self.infcx.root_var(diverging_vid);
+ let root_vid = self.root_var(diverging_vid);
let can_reach_non_diverging = coercion_graph
.depth_first_search(root_vid)
.any(|n| roots_reachable_from_non_diverging.visited(n));
let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false };
for (vid, rel) in relationships.iter() {
- if self.infcx.root_var(*vid) == root_vid {
+ if self.root_var(*vid) == root_vid {
relationship.self_in_trait |= rel.self_in_trait;
relationship.output |= rel.output;
}
})
.collect();
debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges);
- let num_ty_vars = self.infcx.num_ty_vars();
+ let num_ty_vars = self.num_ty_vars();
VecGraph::new(num_ty_vars, coercion_edges)
}
/// If `ty` is an unresolved type variable, returns its root vid.
fn root_vid(&self, ty: Ty<'tcx>) -> Option<ty::TyVid> {
- Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?))
+ Some(self.root_var(self.shallow_resolve(ty).ty_vid()?))
}
}
if !method.substs.is_empty() {
let method_generics = self.tcx.generics_of(method.def_id);
if !method_generics.params.is_empty() {
- let user_type_annotation = self.infcx.probe(|_| {
+ let user_type_annotation = self.probe(|_| {
let user_substs = UserSubsts {
substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
let i = param.index as usize;
if i < method_generics.parent_count {
- self.infcx.var_for_def(DUMMY_SP, param)
+ self.var_for_def(DUMMY_SP, param)
} else {
method.substs[i]
}
user_self_ty: None, // not relevant here
};
- self.infcx.canonicalize_user_type_annotation(UserType::TypeOf(
+ self.canonicalize_user_type_annotation(UserType::TypeOf(
method.def_id,
user_substs,
))
debug!("fcx {}", self.tag());
if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
- let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf(
+ let canonicalized = self.canonicalize_user_type_annotation(UserType::TypeOf(
def_id,
UserSubsts { substs, user_self_ty },
));
debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
if Self::can_contain_user_lifetime_bounds(ty) {
- let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty));
+ let c_ty = self.canonicalize_response(UserType::Ty(ty));
debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
}
if let ty::subst::GenericArgKind::Type(ty) = ty.unpack()
&& let ty::Opaque(def_id, _) = *ty.kind()
&& let Some(def_id) = def_id.as_local()
- && self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() {
+ && self.opaque_type_origin(def_id, DUMMY_SP).is_some() {
return None;
}
}
} else {
self.tcx.bound_type_of(def_id)
};
- let substs = self.infcx.fresh_substs_for_item(span, def_id);
+ let substs = self.fresh_substs_for_item(span, def_id);
let ty = item_ty.subst(self.tcx, substs);
self.write_resolution(hir_id, Ok((def_kind, def_id)));
use crate::structured_errors::StructuredDiagnostic;
use rustc_ast as ast;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticId, MultiSpan};
+use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
"argument"
),
potentially_plural_count(provided_args.len(), "argument"),
- if provided_args.len() == 1 { "was" } else { "were" }
+ pluralize!("was", provided_args.len())
),
DiagnosticId::Error(err_code.to_owned()),
);
if c_variadic { "at least " } else { "" },
potentially_plural_count(formal_and_expected_inputs.len(), "argument"),
potentially_plural_count(provided_args.len(), "argument"),
- if provided_args.len() == 1 { "was" } else { "were" }
+ pluralize!("was", provided_args.len())
),
DiagnosticId::Error(err_code.to_owned()),
)
/// ```
fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
let check_in_progress = |elem: &hir::Expr<'_>| {
- self.in_progress_typeck_results
- .and_then(|typeck_results| typeck_results.borrow().node_type_opt(elem.hir_id))
- .and_then(|ty| {
- if ty.is_never() {
- None
- } else {
- Some(match elem.kind {
- // Point at the tail expression when possible.
- hir::ExprKind::Block(block, _) => {
- block.expr.map_or(block.span, |e| e.span)
- }
- _ => elem.span,
- })
- }
- })
+ self.typeck_results.borrow().node_type_opt(elem.hir_id).filter(|ty| !ty.is_never()).map(
+ |_| match elem.kind {
+ // Point at the tail expression when possible.
+ hir::ExprKind::Block(block, _) => block.expr.map_or(block.span, |e| e.span),
+ _ => elem.span,
+ },
+ )
};
if let hir::ExprKind::If(_, _, Some(el)) = expr.kind {
use super::callee::DeferredCallResolution;
-use super::MaybeInProgressTables;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
pub struct Inherited<'a, 'tcx> {
pub(super) infcx: InferCtxt<'a, 'tcx>,
- pub(super) typeck_results: super::MaybeInProgressTables<'a, 'tcx>,
+ pub(super) typeck_results: &'a RefCell<ty::TypeckResults<'tcx>>,
pub(super) locals: RefCell<HirIdMap<super::LocalTy<'tcx>>>,
let tcx = infcx.tcx;
let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
let body_id = tcx.hir().maybe_body_owned_by(item_id);
+ let typeck_results =
+ infcx.in_progress_typeck_results.expect("building `FnCtxt` without typeck results");
Inherited {
- typeck_results: MaybeInProgressTables {
- maybe_typeck_results: infcx.in_progress_typeck_results,
- },
+ typeck_results,
infcx,
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)),
locals: RefCell::new(Default::default()),
OP: FnOnce(ProbeContext<'a, 'tcx>) -> Result<R, MethodError<'tcx>>,
{
let mut orig_values = OriginalQueryValues::default();
- let param_env_and_self_ty = self.infcx.canonicalize_query(
+ let param_env_and_self_ty = self.canonicalize_query(
ParamEnvAnd { param_env: self.param_env, value: self_ty },
&mut orig_values,
);
let steps = if mode == Mode::MethodCall {
self.tcx.method_autoderef_steps(param_env_and_self_ty)
} else {
- self.infcx.probe(|_| {
+ self.probe(|_| {
// Mode::Path - the deref steps is "trivial". This turns
// our CanonicalQuery into a "trivial" QueryResponse. This
// is a bit inefficient, but I don't think that writing
.join("\n");
let actual_prefix = actual.prefix_string(self.tcx);
info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
- let (primary_message, label) = if unimplemented_traits.len() == 1
- && unimplemented_traits_only
- {
- unimplemented_traits
- .into_iter()
- .next()
- .map(|(_, (trait_ref, obligation))| {
- if trait_ref.self_ty().references_error()
- || actual.references_error()
- {
- // Avoid crashing.
- return (None, None);
- }
- let OnUnimplementedNote { message, label, .. } =
- self.infcx.on_unimplemented_note(trait_ref, &obligation);
- (message, label)
- })
- .unwrap_or((None, None))
- } else {
- (None, None)
- };
+ let (primary_message, label) =
+ if unimplemented_traits.len() == 1 && unimplemented_traits_only {
+ unimplemented_traits
+ .into_iter()
+ .next()
+ .map(|(_, (trait_ref, obligation))| {
+ if trait_ref.self_ty().references_error()
+ || actual.references_error()
+ {
+ // Avoid crashing.
+ return (None, None);
+ }
+ let OnUnimplementedNote { message, label, .. } =
+ self.on_unimplemented_note(trait_ref, &obligation);
+ (message, label)
+ })
+ .unwrap_or((None, None))
+ } else {
+ (None, None)
+ };
let primary_message = primary_message.unwrap_or_else(|| format!(
"the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
));
add a `use` for {one_of_them}:",
an = if candidates.len() == 1 { "an" } else { "" },
s = pluralize!(candidates.len()),
- were = if candidates.len() == 1 { "was" } else { "were" },
+ were = pluralize!("was", candidates.len()),
one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
);
self.suggest_use_candidates(&mut err, help, candidates);
call: &hir::Expr<'_>,
span: Span,
) {
- let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
+ let output_ty = match self.get_impl_future_output_ty(ty) {
Some(output_ty) => self.resolve_vars_if_possible(output_ty).skip_binder(),
_ => return,
};
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
-
-use std::cell::{Ref, RefCell, RefMut};
+use std::cell::RefCell;
use crate::require_c_abi_if_c_variadic;
use crate::util::common::indenter;
TupleArguments,
}
-/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
-#[derive(Copy, Clone)]
-struct MaybeInProgressTables<'a, 'tcx> {
- maybe_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
-}
-
-impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
- fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> {
- match self.maybe_typeck_results {
- Some(typeck_results) => typeck_results.borrow(),
- None => bug!(
- "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results"
- ),
- }
- }
-
- fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> {
- match self.maybe_typeck_results {
- Some(typeck_results) => typeck_results.borrow_mut(),
- None => bug!(
- "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results"
- ),
- }
- }
-}
-
fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
}
suggest_deref_binop(lhs_deref_ty);
} else if is_assign == IsAssign::No
&& let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() {
- if self.infcx.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) {
+ if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) {
suggest_deref_binop(*lhs_deref_ty);
}
}
_ => None,
};
- self.infcx.suggest_restricting_param_bound(
+ self.suggest_restricting_param_bound(
&mut err,
trait_pred,
proj_pred,
error.obligation.predicate.to_opt_poly_trait_pred()
});
for pred in predicates {
- self.infcx.suggest_restricting_param_bound(
+ self.suggest_restricting_param_bound(
&mut err,
pred,
None,
let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?;
- let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
+ let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id));
let ty = match closure_clause {
hir::CaptureBy::Value => ty, // For move closure the capture kind should be by value
closure_clause: hir::CaptureBy,
var_hir_id: hir::HirId,
) -> Option<FxHashSet<UpvarMigrationInfo>> {
- let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
+ let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id));
if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) {
debug!("does not have significant drop");
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
unsatisfied_bounds.sort();
if !unsatisfied_bounds.is_empty() {
- let plural = if unsatisfied_bounds.len() > 1 { "s" } else { "" };
+ let plural = pluralize!(unsatisfied_bounds.len());
let mut err = tcx.sess.struct_span_err(
gat_item_hir.span,
&format!("missing required bound{} on `{}`", plural, gat_item_hir.ident),
// (e.g. keep `for<'a>` named `for<'a>`).
// This allows NLL to generate error messages that
// refer to the higher-ranked lifetime names written by the user.
- EraseEarlyRegions { tcx: self.infcx.tcx }.fold_ty(t)
+ EraseEarlyRegions { tcx: self.tcx }.fold_ty(t)
}
Err(_) => {
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
match self.infcx.fully_resolve(ct) {
- Ok(ct) => self.infcx.tcx.erase_regions(ct),
+ Ok(ct) => self.tcx.erase_regions(ct),
Err(_) => {
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
self.report_const_error(ct);
// from the trait itself that *shouldn't* be shown as the source of
// an obligation and instead be skipped. Otherwise we'd use
// `tcx.def_span(def_id);`
+
+ let constness = if tcx.has_attr(def_id, sym::const_trait) {
+ ty::BoundConstness::ConstIfConst
+ } else {
+ ty::BoundConstness::NotConst
+ };
+
let span = rustc_span::DUMMY_SP;
result.predicates =
tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
- ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(tcx),
+ ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
span,
))));
}
}
} else if attr.has_name(sym::rustc_allocator_nounwind) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+ } else if attr.has_name(sym::rustc_reallocator) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
+ } else if attr.has_name(sym::rustc_deallocator) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
+ } else if attr.has_name(sym::rustc_allocator_zeroed) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
} else if attr.has_name(sym::naked) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
} else if attr.has_name(sym::no_mangle) {
let is_like_elf = !(tcx.sess.target.is_like_osx
|| tcx.sess.target.is_like_windows
|| tcx.sess.target.is_like_wasm);
- codegen_fn_attrs.flags = if is_like_elf {
+ codegen_fn_attrs.flags |= if is_like_elf {
CodegenFnAttrFlags::USED
} else {
CodegenFnAttrFlags::USED_LINKER
tcx.mk_adt(def, substs)
}
ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
- find_opaque_ty_constraints(tcx, def_id)
+ find_opaque_ty_constraints_for_tait(tcx, def_id)
}
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), .. }) => {
- let concrete_ty = tcx
- .mir_borrowck(owner)
- .concrete_opaque_types
- .get(&def_id)
- .copied()
- .map(|concrete| concrete.ty)
- .unwrap_or_else(|| {
- let table = tcx.typeck(owner);
- if let Some(_) = table.tainted_by_errors {
- // Some error in the
- // owner fn prevented us from populating
- // the `concrete_opaque_types` table.
- tcx.ty_error()
- } else {
- table.concrete_opaque_types.get(&def_id).copied().unwrap_or_else(|| {
- // We failed to resolve the opaque type or it
- // resolves to itself. We interpret this as the
- // no values of the hidden type ever being constructed,
- // so we can just make the hidden type be `!`.
- // For backwards compatibility reasons, we fall back to
- // `()` until we the diverging default is changed.
- Some(tcx.mk_diverging_default())
- }).expect("RPIT always have a hidden type from typeck")
- }
- });
- debug!("concrete_ty = {:?}", concrete_ty);
- concrete_ty
+ find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
}
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
/// fn b<T>() -> Foo<T, u32> { .. }
/// ```
///
-fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
+fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
use rustc_hir::{Expr, ImplItem, Item, TraitItem};
struct ConstraintLocator<'tcx> {
impl ConstraintLocator<'_> {
#[instrument(skip(self), level = "debug")]
- fn check(&mut self, def_id: LocalDefId) {
+ fn check(&mut self, item_def_id: LocalDefId) {
// Don't try to check items that cannot possibly constrain the type.
- if !self.tcx.has_typeck_results(def_id) {
+ if !self.tcx.has_typeck_results(item_def_id) {
debug!("no constraint: no typeck results");
return;
}
// // because we again need to reveal `Foo` so we can check whether the
// // constant does not contain interior mutability.
// ```
- let tables = self.tcx.typeck(def_id);
+ let tables = self.tcx.typeck(item_def_id);
if let Some(_) = tables.tainted_by_errors {
self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() });
return;
}
- if tables.concrete_opaque_types.get(&self.def_id).is_none() {
+ if !tables.concrete_opaque_types.contains_key(&self.def_id) {
debug!("no constraints in typeck results");
return;
}
// Use borrowck to get the type with unerased regions.
- let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
+ let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
debug!(?concrete_opaque_types);
- for &(def_id, concrete_type) in concrete_opaque_types {
- if def_id != self.def_id {
- // Ignore constraints for other opaque types.
- continue;
- }
-
+ if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
debug!(?concrete_type, "found constraint");
-
if let Some(prev) = self.found {
if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() {
prev.report_mismatch(&concrete_type, self.tcx);
}
}
+fn find_opaque_ty_constraints_for_rpit(
+ tcx: TyCtxt<'_>,
+ def_id: LocalDefId,
+ owner_def_id: LocalDefId,
+) -> Ty<'_> {
+ use rustc_hir::{Expr, ImplItem, Item, TraitItem};
+
+ struct ConstraintChecker<'tcx> {
+ tcx: TyCtxt<'tcx>,
+
+ /// def_id of the opaque type whose defining uses are being checked
+ def_id: LocalDefId,
+
+ found: ty::OpaqueHiddenType<'tcx>,
+ }
+
+ impl ConstraintChecker<'_> {
+ #[instrument(skip(self), level = "debug")]
+ fn check(&self, def_id: LocalDefId) {
+ // Use borrowck to get the type with unerased regions.
+ let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
+ debug!(?concrete_opaque_types);
+ for &(def_id, concrete_type) in concrete_opaque_types {
+ if def_id != self.def_id {
+ // Ignore constraints for other opaque types.
+ continue;
+ }
+
+ debug!(?concrete_type, "found constraint");
+
+ if concrete_type.ty != self.found.ty
+ && !(concrete_type, self.found).references_error()
+ {
+ self.found.report_mismatch(&concrete_type, self.tcx);
+ }
+ }
+ }
+ }
+
+ impl<'tcx> intravisit::Visitor<'tcx> for ConstraintChecker<'tcx> {
+ type NestedFilter = nested_filter::OnlyBodies;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
+ }
+ fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
+ if let hir::ExprKind::Closure { .. } = ex.kind {
+ let def_id = self.tcx.hir().local_def_id(ex.hir_id);
+ self.check(def_id);
+ }
+ intravisit::walk_expr(self, ex);
+ }
+ fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
+ trace!(?it.def_id);
+ // The opaque type itself or its children are not within its reveal scope.
+ if it.def_id != self.def_id {
+ self.check(it.def_id);
+ intravisit::walk_item(self, it);
+ }
+ }
+ fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
+ trace!(?it.def_id);
+ // The opaque type itself or its children are not within its reveal scope.
+ if it.def_id != self.def_id {
+ self.check(it.def_id);
+ intravisit::walk_impl_item(self, it);
+ }
+ }
+ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
+ trace!(?it.def_id);
+ self.check(it.def_id);
+ intravisit::walk_trait_item(self, it);
+ }
+ }
+
+ let concrete = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied();
+
+ if let Some(concrete) = concrete {
+ let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id);
+ debug!(?scope);
+ let mut locator = ConstraintChecker { def_id: def_id, tcx, found: concrete };
+
+ match tcx.hir().get(scope) {
+ Node::Item(it) => intravisit::walk_item(&mut locator, it),
+ Node::ImplItem(it) => intravisit::walk_impl_item(&mut locator, it),
+ Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it),
+ other => bug!("{:?} is not a valid scope for an opaque type item", other),
+ }
+ }
+
+ concrete.map(|concrete| concrete.ty).unwrap_or_else(|| {
+ let table = tcx.typeck(owner_def_id);
+ if let Some(_) = table.tainted_by_errors {
+ // Some error in the
+ // owner fn prevented us from populating
+ // the `concrete_opaque_types` table.
+ tcx.ty_error()
+ } else {
+ table
+ .concrete_opaque_types
+ .get(&def_id)
+ .copied()
+ .unwrap_or_else(|| {
+ // We failed to resolve the opaque type or it
+ // resolves to itself. We interpret this as the
+ // no values of the hidden type ever being constructed,
+ // so we can just make the hidden type be `!`.
+ // For backwards compatibility reasons, we fall back to
+ // `()` until we the diverging default is changed.
+ Some(tcx.mk_diverging_default())
+ })
+ .expect("RPIT always have a hidden type from typeck")
+ }
+ })
+}
+
fn infer_placeholder_type<'a>(
tcx: TyCtxt<'a>,
def_id: LocalDefId,
pub struct MissingTypeParams {
pub span: Span,
pub def_span: Span,
- pub missing_type_params: Vec<String>,
+ pub missing_type_params: Vec<Symbol>,
pub empty_generic_args: bool,
}
err.span_suggestion(
self.span,
rustc_errors::fluent::typeck::suggestion,
- format!("{}<{}>", snippet, self.missing_type_params.join(", ")),
+ format!(
+ "{}<{}>",
+ snippet,
+ self.missing_type_params
+ .iter()
+ .map(|n| n.to_string())
+ .collect::<Vec<_>>()
+ .join(", ")
+ ),
Applicability::HasPlaceholders,
);
suggested = true;
let provided_lt_args = self.num_provided_lifetime_args();
let provided_type_or_const_args = self.num_provided_type_or_const_args();
- let get_verb = |num_args| if num_args == 1 { "was" } else { "were" };
-
let (provided_args_str, verb) = match self.gen_args_info {
MissingLifetimes { .. } | ExcessLifetimes { .. } => (
format!("{} lifetime argument{}", provided_lt_args, pluralize!(provided_lt_args)),
- get_verb(provided_lt_args),
+ pluralize!("was", provided_lt_args),
),
MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => (
format!(
provided_type_or_const_args,
pluralize!(provided_type_or_const_args)
),
- get_verb(provided_type_or_const_args),
+ pluralize!("was", provided_type_or_const_args),
),
};
// See https://github.com/rust-lang/rust/issues/73535#event-3477699747
#![cfg(not(target_os = "android"))]
#![feature(btree_drain_filter)]
+#![feature(iter_next_chunk)]
#![feature(map_first_last)]
#![feature(repr_simd)]
#![feature(slice_partition_dedup)]
let mut v = black_box(vec![826u32; 100000]);
b.iter(|| v.retain(|x| *x == 826u32));
}
+
+#[bench]
+fn bench_next_chunk(b: &mut Bencher) {
+ let v = vec![13u8; 2048];
+
+ b.iter(|| {
+ const CHUNK: usize = 8;
+
+ let mut sum = [0u32; CHUNK];
+ let mut iter = black_box(v.clone()).into_iter();
+
+ while let Ok(chunk) = iter.next_chunk::<CHUNK>() {
+ for i in 0..CHUNK {
+ sum[i] += chunk[i] as u32;
+ }
+ }
+
+ sum
+ })
+}
// (the code expanding that attribute macro generates those functions), or to call
// the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
// otherwise.
- // The rustc fork of LLVM also special-cases these function names to be able to optimize them
+ // The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them
// like `malloc`, `realloc`, and `free`, respectively.
#[rustc_allocator]
#[rustc_allocator_nounwind]
fn __rust_alloc(size: usize, align: usize) -> *mut u8;
+ #[cfg_attr(not(bootstrap), rustc_deallocator)]
#[rustc_allocator_nounwind]
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
+ #[cfg_attr(not(bootstrap), rustc_reallocator)]
#[rustc_allocator_nounwind]
fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
+ #[cfg_attr(not(bootstrap), rustc_allocator_zeroed)]
#[rustc_allocator_nounwind]
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
}
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(array_chunks)]
+#![feature(array_into_iter_constructors)]
#![feature(array_methods)]
#![feature(array_windows)]
#![feature(assert_matches)]
#![feature(hasher_prefixfree_extras)]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
+#![feature(iter_next_chunk)]
#![feature(layout_for_ptr)]
+#![feature(maybe_uninit_array_assume_init)]
#![feature(maybe_uninit_slice)]
+#![feature(maybe_uninit_uninit_array)]
#![cfg_attr(test, feature(new_uninit))]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(pattern)]
///
/// ```text
/// 0
-/// 5
-/// 10
-/// 20
-/// 20
-/// 40
+/// 8
+/// 16
+/// 16
+/// 32
+/// 32
/// ```
///
/// At first, we have no memory allocated at all, but as we append to the
use super::AsVecIntoIter;
use crate::alloc::{Allocator, Global};
use crate::raw_vec::RawVec;
+use core::array;
use core::fmt;
use core::intrinsics::arith_offset;
use core::iter::{
FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
};
use core::marker::PhantomData;
-use core::mem::{self, ManuallyDrop};
+use core::mem::{self, ManuallyDrop, MaybeUninit};
#[cfg(not(no_global_oom_handling))]
use core::ops::Deref;
use core::ptr::{self, NonNull};
}
/// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed.
- #[cfg(not(no_global_oom_handling))]
pub(crate) fn forget_remaining_elements(&mut self) {
self.ptr = self.end;
}
self.len()
}
+ #[inline]
+ fn next_chunk<const N: usize>(&mut self) -> Result<[T; N], core::array::IntoIter<T, N>> {
+ let mut raw_ary = MaybeUninit::uninit_array();
+
+ let len = self.len();
+
+ if mem::size_of::<T>() == 0 {
+ if len < N {
+ self.forget_remaining_elements();
+ // Safety: ZSTs can be conjured ex nihilo, only the amount has to be correct
+ return Err(unsafe { array::IntoIter::new_unchecked(raw_ary, 0..len) });
+ }
+
+ self.ptr = unsafe { arith_offset(self.ptr as *const i8, N as isize) as *mut T };
+ // Safety: ditto
+ return Ok(unsafe { MaybeUninit::array_assume_init(raw_ary) });
+ }
+
+ if len < N {
+ // Safety: `len` indicates that this many elements are available and we just checked that
+ // it fits into the array.
+ unsafe {
+ ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, len);
+ self.forget_remaining_elements();
+ return Err(array::IntoIter::new_unchecked(raw_ary, 0..len));
+ }
+ }
+
+ // Safety: `len` is larger than the array size. Copy a fixed amount here to fully initialize
+ // the array.
+ return unsafe {
+ ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, N);
+ self.ptr = self.ptr.add(N);
+ Ok(MaybeUninit::array_assume_init(raw_ary))
+ };
+ }
+
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
where
Self: TrustedRandomAccessNoCoerce,
#![feature(binary_heap_as_slice)]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
+#![feature(iter_next_chunk)]
#![feature(round_char_boundary)]
#![feature(slice_group_by)]
#![feature(slice_partition_dedup)]
use core::alloc::{Allocator, Layout};
+use core::iter::IntoIterator;
use core::ptr::NonNull;
use std::alloc::System;
use std::assert_matches::assert_matches;
assert_eq!([1, 2, 3].into_iter().count(), 3);
}
+#[test]
+fn test_into_iter_next_chunk() {
+ let mut iter = b"lorem".to_vec().into_iter();
+
+ assert_eq!(iter.next_chunk().unwrap(), [b'l', b'o']); // N is inferred as 2
+ assert_eq!(iter.next_chunk().unwrap(), [b'r', b'e', b'm']); // N is inferred as 3
+ assert_eq!(iter.next_chunk::<4>().unwrap_err().as_slice(), &[]); // N is explicitly 4
+}
+
#[test]
fn test_into_iter_clone() {
fn iter_equal<I: Iterator<Item = i32>>(it: I, slice: &[i32]) {
#![stable(feature = "rust1", since = "1.0.0")]
+use crate::marker::Destruct;
+
use self::Ordering::*;
/// Trait for equality comparisons which are [partial equivalence
pub struct Reverse<T>(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T);
#[stable(feature = "reverse_cmp_key", since = "1.19.0")]
-impl<T: PartialOrd> PartialOrd for Reverse<T> {
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+impl<T: ~const PartialOrd> const PartialOrd for Reverse<T> {
#[inline]
fn partial_cmp(&self, other: &Reverse<T>) -> Option<Ordering> {
other.0.partial_cmp(&self.0)
#[doc(alias = ">=")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Ord"]
+#[const_trait]
pub trait Ord: Eq + PartialOrd<Self> {
/// This method returns an [`Ordering`] between `self` and `other`.
///
fn max(self, other: Self) -> Self
where
Self: Sized,
+ Self: ~const Destruct,
{
- max_by(self, other, Ord::cmp)
+ // HACK(fee1-dead): go back to using `self.max_by(other, Ord::cmp)`
+ // when trait methods are allowed to be used when a const closure is
+ // expected.
+ match self.cmp(&other) {
+ Ordering::Less | Ordering::Equal => other,
+ Ordering::Greater => self,
+ }
}
/// Compares and returns the minimum of two values.
fn min(self, other: Self) -> Self
where
Self: Sized,
+ Self: ~const Destruct,
{
- min_by(self, other, Ord::cmp)
+ // HACK(fee1-dead): go back to using `self.min_by(other, Ord::cmp)`
+ // when trait methods are allowed to be used when a const closure is
+ // expected.
+ match self.cmp(&other) {
+ Ordering::Less | Ordering::Equal => self,
+ Ordering::Greater => other,
+ }
}
/// Restrict a value to a certain interval.
fn clamp(self, min: Self, max: Self) -> Self
where
Self: Sized,
+ Self: ~const Destruct,
+ Self: ~const PartialOrd,
{
assert!(min <= max);
if self < min {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl Ord for Ordering {
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+impl const Ord for Ordering {
#[inline]
fn cmp(&self, other: &Ordering) -> Ordering {
(*self as i32).cmp(&(*other as i32))
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialOrd for Ordering {
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+impl const PartialOrd for Ordering {
#[inline]
fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
(*self as i32).partial_cmp(&(*other as i32))
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_min")]
-pub fn min<T: Ord>(v1: T, v2: T) -> T {
+pub const fn min<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
v1.min(v2)
}
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_max")]
-pub fn max<T: Ord>(v1: T, v2: T) -> T {
+pub const fn max<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
v1.max(v2)
}
macro_rules! partial_eq_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl PartialEq for $t {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const PartialEq for $t {
#[inline]
fn eq(&self, other: &$t) -> bool { (*self) == (*other) }
#[inline]
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl PartialEq for () {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const PartialEq for () {
#[inline]
fn eq(&self, _other: &()) -> bool {
true
macro_rules! partial_ord_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl PartialOrd for $t {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const PartialOrd for $t {
#[inline]
fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
match (*self <= *other, *self >= *other) {
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl PartialOrd for () {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const PartialOrd for () {
#[inline]
fn partial_cmp(&self, _: &()) -> Option<Ordering> {
Some(Equal)
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl PartialOrd for bool {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const PartialOrd for bool {
#[inline]
fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
Some(self.cmp(other))
macro_rules! ord_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl PartialOrd for $t {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const PartialOrd for $t {
#[inline]
fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
Some(self.cmp(other))
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl Ord for $t {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const Ord for $t {
#[inline]
fn cmp(&self, other: &$t) -> Ordering {
// The order here is important to generate more optimal assembly.
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl Ord for () {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const Ord for () {
#[inline]
fn cmp(&self, _other: &()) -> Ordering {
Equal
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl Ord for bool {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const Ord for bool {
#[inline]
fn cmp(&self, other: &bool) -> Ordering {
// Casting to i8's and converting the difference to an Ordering generates
ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
#[unstable(feature = "never_type", issue = "35121")]
- impl PartialEq for ! {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const PartialEq for ! {
fn eq(&self, _: &!) -> bool {
*self
}
impl Eq for ! {}
#[unstable(feature = "never_type", issue = "35121")]
- impl PartialOrd for ! {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const PartialOrd for ! {
fn partial_cmp(&self, _: &!) -> Option<Ordering> {
*self
}
}
#[unstable(feature = "never_type", issue = "35121")]
- impl Ord for ! {
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl const Ord for ! {
fn cmp(&self, _: &!) -> Ordering {
*self
}
// & pointers
#[stable(feature = "rust1", since = "1.0.0")]
- impl<A: ?Sized, B: ?Sized> PartialEq<&B> for &A
+ #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+ impl<A: ?Sized, B: ?Sized> const PartialEq<&B> for &A
where
- A: PartialEq<B>,
+ A: ~const PartialEq<B>,
{
#[inline]
fn eq(&self, other: &&B) -> bool {
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
#[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unreachable_unchecked() -> ! {
// SAFETY: the safety contract for `intrinsics::unreachable` must
// be upheld by the caller.
#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[inline]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[inline]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
///
/// * `dst` must be properly aligned.
///
-/// Additionally, the caller must ensure that writing `count *
-/// size_of::<T>()` bytes to the given region of memory results in a valid
-/// value of `T`. Using a region of memory typed as a `T` that contains an
-/// invalid value of `T` is undefined behavior.
-///
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
/// `0`, the pointer must be non-null and properly aligned.
///
+/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB)
+/// later if the written bytes are not a valid representation of some `T`. For instance, the
+/// following is an **incorrect** use of this function:
+///
+/// ```rust,no_run
+/// unsafe {
+/// let mut value: u8 = 0;
+/// let ptr: *mut bool = &mut value as *mut u8 as *mut bool;
+/// let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`.
+/// ptr.write_bytes(42u8, 1); // This function itself does not cause UB...
+/// let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️
+/// }
+/// ```
+///
/// [valid]: crate::ptr#safety
///
/// # Examples
/// }
/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
/// ```
-///
-/// Creating an invalid value:
-///
-/// ```
-/// use std::ptr;
-///
-/// let mut v = Box::new(0i32);
-///
-/// unsafe {
-/// // Leaks the previously held value by overwriting the `Box<T>` with
-/// // a null pointer.
-/// ptr::write_bytes(&mut v as *mut Box<i32>, 0, 1);
-/// }
-///
-/// // At this point, using or dropping `v` results in undefined behavior.
-/// // drop(v); // ERROR
-///
-/// // Even leaking `v` "uses" it, and hence is undefined behavior.
-/// // mem::forget(v); // ERROR
-///
-/// // In fact, `v` is invalid according to basic type layout invariants, so *any*
-/// // operation touching it is undefined behavior.
-/// // let v2 = v; // ERROR
-///
-/// unsafe {
-/// // Let us instead put in a valid value
-/// ptr::write(&mut v as *mut Box<i32>, Box::new(42i32));
-/// }
-///
-/// // Now the box is fine
-/// assert_eq!(*v, 42);
-/// ```
#[doc(alias = "memset")]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
#![feature(const_cell_into_inner)]
#![feature(const_char_convert)]
#![feature(const_clone)]
+#![feature(const_cmp)]
#![feature(const_discriminant)]
#![feature(const_eval_select)]
#![feature(const_float_bits_conv)]
///
/// This function will unsafely assume the pointer `src` is valid for [`size_of::<U>`][size_of]
/// bytes by transmuting `&T` to `&U` and then reading the `&U` (except that this is done in a way
-/// that is correct even when `&U` makes stricter alignment requirements than `&T`). It will also
+/// that is correct even when `&U` has stricter alignment requirements than `&T`). It will also
/// unsafely create a copy of the contained value instead of moving out of `src`.
///
/// It is not a compile-time error if `T` and `U` have different sizes, but it
#[stable(feature = "discriminant_value", since = "1.21.0")]
#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
#[cfg_attr(not(test), rustc_diagnostic_item = "mem_discriminant")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
Discriminant(intrinsics::discriminant_value(v))
}
without modifying the original"]
#[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_add`.
without modifying the original"]
#[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_sub`.
without modifying the original"]
#[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_mul`.
without modifying the original"]
#[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shl`.
without modifying the original"]
#[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shr`.
without modifying the original"]
#[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_add`.
without modifying the original"]
#[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_sub`.
without modifying the original"]
#[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_mul`.
without modifying the original"]
#[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shl`.
without modifying the original"]
#[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
// SAFETY: the caller must uphold the safety contract for
// `unchecked_shr`.
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn offset(self, count: isize) -> *const T
where
T: Sized,
#[inline(always)]
#[unstable(feature = "pointer_byte_offsets", issue = "96283")]
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn byte_offset(self, count: isize) -> Self {
// SAFETY: the caller must uphold the safety contract for `offset`.
let this = unsafe { self.cast::<u8>().offset(count).cast::<()>() };
#[stable(feature = "ptr_offset_from", since = "1.47.0")]
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
#[inline]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn offset_from(self, origin: *const T) -> isize
where
T: Sized,
#[inline(always)]
#[unstable(feature = "pointer_byte_offsets", issue = "96283")]
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize {
// SAFETY: the caller must uphold the safety contract for `offset_from`.
unsafe { self.cast::<u8>().offset_from(origin.cast::<u8>()) }
/// }
///
/// // This would be incorrect, as the pointers are not correctly ordered:
- /// // ptr1.offset_from(ptr2)
+ /// // ptr1.sub_ptr(ptr2)
/// ```
#[unstable(feature = "ptr_sub_ptr", issue = "95892")]
#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
#[inline]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn sub_ptr(self, origin: *const T) -> usize
where
T: Sized,
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn add(self, count: usize) -> Self
where
T: Sized,
#[inline(always)]
#[unstable(feature = "pointer_byte_offsets", issue = "96283")]
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn byte_add(self, count: usize) -> Self {
// SAFETY: the caller must uphold the safety contract for `add`.
let this = unsafe { self.cast::<u8>().add(count).cast::<()>() };
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[inline]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn sub(self, count: usize) -> Self
where
T: Sized,
#[inline(always)]
#[unstable(feature = "pointer_byte_offsets", issue = "96283")]
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn byte_sub(self, count: usize) -> Self {
// SAFETY: the caller must uphold the safety contract for `sub`.
let this = unsafe { self.cast::<u8>().sub(count).cast::<()>() };
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn copy_to(self, dest: *mut T, count: usize)
where
T: Sized,
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
where
T: Sized,
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn offset(self, count: isize) -> *mut T
where
T: Sized,
#[inline(always)]
#[unstable(feature = "pointer_byte_offsets", issue = "96283")]
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn byte_offset(self, count: isize) -> Self {
// SAFETY: the caller must uphold the safety contract for `offset`.
let this = unsafe { self.cast::<u8>().offset(count).cast::<()>() };
#[stable(feature = "ptr_offset_from", since = "1.47.0")]
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn offset_from(self, origin: *const T) -> isize
where
T: Sized,
#[inline(always)]
#[unstable(feature = "pointer_byte_offsets", issue = "96283")]
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize {
// SAFETY: the caller must uphold the safety contract for `offset_from`.
unsafe { self.cast::<u8>().offset_from(origin.cast::<u8>()) }
#[unstable(feature = "ptr_sub_ptr", issue = "95892")]
#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
#[inline]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn sub_ptr(self, origin: *const T) -> usize
where
T: Sized,
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn add(self, count: usize) -> Self
where
T: Sized,
#[inline(always)]
#[unstable(feature = "pointer_byte_offsets", issue = "96283")]
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn byte_add(self, count: usize) -> Self {
// SAFETY: the caller must uphold the safety contract for `add`.
let this = unsafe { self.cast::<u8>().add(count).cast::<()>() };
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[inline]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn sub(self, count: usize) -> Self
where
T: Sized,
#[inline(always)]
#[unstable(feature = "pointer_byte_offsets", issue = "96283")]
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn byte_sub(self, count: usize) -> Self {
// SAFETY: the caller must uphold the safety contract for `sub`.
let this = unsafe { self.cast::<u8>().sub(count).cast::<()>() };
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn copy_to(self, dest: *mut T, count: usize)
where
T: Sized,
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
where
T: Sized,
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn copy_from(self, src: *const T, count: usize)
where
T: Sized,
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline(always)]
+ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize)
where
T: Sized,
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ChunksMut<'a, T: 'a> {
- v: &'a mut [T],
+ /// # Safety
+ /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
+ /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
+ /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
+ /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
+ /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
+ v: *mut [T],
chunk_size: usize,
+ _marker: PhantomData<&'a mut T>,
}
impl<'a, T: 'a> ChunksMut<'a, T> {
#[inline]
pub(super) fn new(slice: &'a mut [T], size: usize) -> Self {
- Self { v: slice, chunk_size: size }
+ Self { v: slice, chunk_size: size, _marker: PhantomData }
}
}
None
} else {
let sz = cmp::min(self.v.len(), self.chunk_size);
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(sz);
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (head, tail) = unsafe { self.v.split_at_mut(sz) };
self.v = tail;
- Some(head)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *head })
}
}
Some(sum) => cmp::min(self.v.len(), sum),
None => self.v.len(),
};
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(end);
- let (_, nth) = head.split_at_mut(start);
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (head, tail) = unsafe { self.v.split_at_mut(end) };
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (_, nth) = unsafe { head.split_at_mut(start) };
self.v = tail;
- Some(nth)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *nth })
}
}
None
} else {
let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
- Some(&mut self.v[start..])
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *self.v.get_unchecked_mut(start..) })
}
}
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let start = idx * self.chunk_size;
- // SAFETY: see comments for `Chunks::__iterator_get_unchecked`.
+ // SAFETY: see comments for `Chunks::__iterator_get_unchecked` and `self.v`.
//
// Also note that the caller also guarantees that we're never called
// with the same index again, and that no other methods that will
} else {
let remainder = self.v.len() % self.chunk_size;
let sz = if remainder != 0 { remainder } else { self.chunk_size };
- let tmp = mem::replace(&mut self.v, &mut []);
- let tmp_len = tmp.len();
+ let len = self.v.len();
// SAFETY: Similar to `Chunks::next_back`
- let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) };
+ let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) };
self.v = head;
- Some(tail)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *tail })
}
}
Some(res) => cmp::min(self.v.len(), res),
None => self.v.len(),
};
- let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
- let (head, nth_back) = temp.split_at_mut(start);
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (temp, _tail) = unsafe { self.v.split_at_mut(end) };
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (head, nth_back) = unsafe { temp.split_at_mut(start) };
self.v = head;
- Some(nth_back)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *nth_back })
}
}
}
#[stable(feature = "chunks_exact", since = "1.31.0")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ChunksExactMut<'a, T: 'a> {
- v: &'a mut [T],
- rem: &'a mut [T],
+ /// # Safety
+ /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
+ /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
+ /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
+ /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
+ /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
+ v: *mut [T],
+ rem: &'a mut [T], // The iterator never yields from here, so this can be unique
chunk_size: usize,
+ _marker: PhantomData<&'a mut T>,
}
impl<'a, T> ChunksExactMut<'a, T> {
let fst_len = slice.len() - rem;
// SAFETY: 0 <= fst_len <= slice.len() by construction above
let (fst, snd) = unsafe { slice.split_at_mut_unchecked(fst_len) };
- Self { v: fst, rem: snd, chunk_size }
+ Self { v: fst, rem: snd, chunk_size, _marker: PhantomData }
}
/// Returns the remainder of the original slice that is not going to be
if self.v.len() < self.chunk_size {
None
} else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(self.chunk_size);
+ // SAFETY: self.chunk_size is inbounds because we compared above against self.v.len()
+ let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) };
self.v = tail;
- Some(head)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *head })
}
}
self.v = &mut [];
None
} else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let (_, snd) = tmp.split_at_mut(start);
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (_, snd) = unsafe { self.v.split_at_mut(start) };
self.v = snd;
self.next()
}
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let start = idx * self.chunk_size;
- // SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`.
+ // SAFETY: see comments for `Chunks::__iterator_get_unchecked` and `self.v`.
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
}
}
if self.v.len() < self.chunk_size {
None
} else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let tmp_len = tmp.len();
- let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
+ // SAFETY: This subtraction is inbounds because of the check above
+ let (head, tail) = unsafe { self.v.split_at_mut(self.v.len() - self.chunk_size) };
self.v = head;
- Some(tail)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *tail })
}
}
} else {
let start = (len - 1 - n) * self.chunk_size;
let end = start + self.chunk_size;
- let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
- let (head, nth_back) = temp.split_at_mut(start);
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (temp, _tail) = unsafe { mem::replace(&mut self.v, &mut []).split_at_mut(end) };
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (head, nth_back) = unsafe { temp.split_at_mut(start) };
self.v = head;
- Some(nth_back)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *nth_back })
}
}
}
#[stable(feature = "rchunks", since = "1.31.0")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct RChunksMut<'a, T: 'a> {
- v: &'a mut [T],
+ /// # Safety
+ /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
+ /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
+ /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
+ /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
+ /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
+ v: *mut [T],
chunk_size: usize,
+ _marker: PhantomData<&'a mut T>,
}
impl<'a, T: 'a> RChunksMut<'a, T> {
#[inline]
pub(super) fn new(slice: &'a mut [T], size: usize) -> Self {
- Self { v: slice, chunk_size: size }
+ Self { v: slice, chunk_size: size, _marker: PhantomData }
}
}
None
} else {
let sz = cmp::min(self.v.len(), self.chunk_size);
- let tmp = mem::replace(&mut self.v, &mut []);
- let tmp_len = tmp.len();
+ let len = self.v.len();
// SAFETY: split_at_mut_unchecked just requires the argument be less
// than the length. This could only happen if the expression
- // `tmp_len - sz` overflows. This could only happen if `sz >
- // tmp_len`, which is impossible as we initialize it as the `min` of
- // `self.v.len()` (e.g. `tmp_len`) and `self.chunk_size`.
- let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) };
+ // `len - sz` overflows. This could only happen if `sz >
+ // len`, which is impossible as we initialize it as the `min` of
+ // `self.v.len()` (e.g. `len`) and `self.chunk_size`.
+ let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) };
self.v = head;
- Some(tail)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *tail })
}
}
Some(sum) => sum,
None => 0,
};
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(start);
- let (nth, _) = tail.split_at_mut(end - start);
+ // SAFETY: This type ensures that self.v is a valid pointer with a correct len.
+ // Therefore the bounds check in split_at_mut guarantess the split point is inbounds.
+ let (head, tail) = unsafe { self.v.split_at_mut(start) };
+ // SAFETY: This type ensures that self.v is a valid pointer with a correct len.
+ // Therefore the bounds check in split_at_mut guarantess the split point is inbounds.
+ let (nth, _) = unsafe { tail.split_at_mut(end - start) };
self.v = head;
- Some(nth)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *nth })
}
}
} else {
let rem = self.v.len() % self.chunk_size;
let end = if rem == 0 { self.chunk_size } else { rem };
- Some(&mut self.v[0..end])
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *self.v.get_unchecked_mut(0..end) })
}
}
Some(start) => start,
};
// SAFETY: see comments for `RChunks::__iterator_get_unchecked` and
- // `ChunksMut::__iterator_get_unchecked`
+ // `ChunksMut::__iterator_get_unchecked`, `self.v`.
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
}
}
} else {
let remainder = self.v.len() % self.chunk_size;
let sz = if remainder != 0 { remainder } else { self.chunk_size };
- let tmp = mem::replace(&mut self.v, &mut []);
// SAFETY: Similar to `Chunks::next_back`
- let (head, tail) = unsafe { tmp.split_at_mut_unchecked(sz) };
+ let (head, tail) = unsafe { self.v.split_at_mut_unchecked(sz) };
self.v = tail;
- Some(head)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *head })
}
}
let offset_from_end = (len - 1 - n) * self.chunk_size;
let end = self.v.len() - offset_from_end;
let start = end.saturating_sub(self.chunk_size);
- let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
- let (_, nth_back) = tmp.split_at_mut(start);
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (tmp, tail) = unsafe { self.v.split_at_mut(end) };
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (_, nth_back) = unsafe { tmp.split_at_mut(start) };
self.v = tail;
- Some(nth_back)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *nth_back })
}
}
}
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let end = self.v.len() - idx * self.chunk_size;
let start = end - self.chunk_size;
- // SAFETY:
- // SAFETY: mostmy identical to `Chunks::__iterator_get_unchecked`.
+ // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`.
unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
}
}
#[stable(feature = "rchunks", since = "1.31.0")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct RChunksExactMut<'a, T: 'a> {
- v: &'a mut [T],
+ /// # Safety
+ /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
+ /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
+ /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
+ /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
+ /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
+ v: *mut [T],
rem: &'a mut [T],
chunk_size: usize,
}
if self.v.len() < self.chunk_size {
None
} else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let tmp_len = tmp.len();
- let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
+ let len = self.v.len();
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (head, tail) = unsafe { self.v.split_at_mut(len - self.chunk_size) };
self.v = head;
- Some(tail)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *tail })
}
}
self.v = &mut [];
None
} else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let tmp_len = tmp.len();
- let (fst, _) = tmp.split_at_mut(tmp_len - end);
+ let len = self.v.len();
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (fst, _) = unsafe { self.v.split_at_mut(len - end) };
self.v = fst;
self.next()
}
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let end = self.v.len() - idx * self.chunk_size;
let start = end - self.chunk_size;
- // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked`.
+ // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked` and `self.v`.
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
}
}
if self.v.len() < self.chunk_size {
None
} else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(self.chunk_size);
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) };
self.v = tail;
- Some(head)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *head })
}
}
let offset = (len - n) * self.chunk_size;
let start = self.v.len() - offset;
let end = start + self.chunk_size;
- let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
- let (_, nth_back) = tmp.split_at_mut(start);
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (tmp, tail) = unsafe { self.v.split_at_mut(end) };
+ // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+ let (_, nth_back) = unsafe { tmp.split_at_mut(start) };
self.v = tail;
- Some(nth_back)
+ // SAFETY: Nothing else points to or will point to the contents of this slice.
+ Some(unsafe { &mut *nth_back })
}
}
}
assert_eq!(v1, [13, 14, 19, 20, 14]);
}
+#[test]
+fn test_chunks_mut_zip_aliasing() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let mut it = v1.chunks_mut(2).zip(v2.chunks(2));
+ let first = it.next().unwrap();
+ let _ = it.next().unwrap();
+ assert_eq!(first, (&mut [0, 1][..], &[6, 7][..]));
+}
+
+#[test]
+fn test_chunks_exact_mut_zip_aliasing() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let mut it = v1.chunks_exact_mut(2).zip(v2.chunks(2));
+ let first = it.next().unwrap();
+ let _ = it.next().unwrap();
+ assert_eq!(first, (&mut [0, 1][..], &[6, 7][..]));
+}
+
+#[test]
+fn test_rchunks_mut_zip_aliasing() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let mut it = v1.rchunks_mut(2).zip(v2.chunks(2));
+ let first = it.next().unwrap();
+ let _ = it.next().unwrap();
+ assert_eq!(first, (&mut [3, 4][..], &[6, 7][..]));
+}
+
+#[test]
+fn test_rchunks_exact_mut_zip_aliasing() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let mut it = v1.rchunks_exact_mut(2).zip(v2.chunks(2));
+ let first = it.next().unwrap();
+ let _ = it.next().unwrap();
+ assert_eq!(first, (&mut [3, 4][..], &[6, 7][..]));
+}
+
#[test]
fn test_chunks_exact_count() {
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
abort();
cfg_if::cfg_if! {
- if #[cfg(unix)] {
+ if #[cfg(any(unix, target_os = "solid_asp3"))] {
unsafe fn abort() -> ! {
libc::abort();
}
} else if #[cfg(any(target_os = "hermit",
- target_os = "solid_asp3",
all(target_vendor = "fortanix", target_env = "sgx")
))] {
unsafe fn abort() -> ! {
bridge::TokenTree::Literal(tt) => TokenTree::Literal(Literal(tt)),
})
}
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.0.size_hint()
+ }
+
+ fn count(self) -> usize {
+ self.0.count()
+ }
}
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
-use crate::cmp;
+mod buffer;
+
use crate::fmt;
use crate::io::{
self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
};
-use crate::mem::MaybeUninit;
+use buffer::Buffer;
/// The `BufReader<R>` struct adds buffering to any reader.
///
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufReader<R> {
inner: R,
- buf: Box<[MaybeUninit<u8>]>,
- pos: usize,
- cap: usize,
- init: usize,
+ buf: Buffer,
}
impl<R: Read> BufReader<R> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
- let buf = Box::new_uninit_slice(capacity);
- BufReader { inner, buf, pos: 0, cap: 0, init: 0 }
+ BufReader { inner, buf: Buffer::with_capacity(capacity) }
}
}
/// ```
#[stable(feature = "bufreader_buffer", since = "1.37.0")]
pub fn buffer(&self) -> &[u8] {
- // SAFETY: self.cap is always <= self.init, so self.buf[self.pos..self.cap] is always init
- unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[self.pos..self.cap]) }
+ self.buf.buffer()
}
/// Returns the number of bytes the internal buffer can hold at once.
/// ```
#[stable(feature = "buffered_io_capacity", since = "1.46.0")]
pub fn capacity(&self) -> usize {
- self.buf.len()
+ self.buf.capacity()
}
/// Unwraps this `BufReader<R>`, returning the underlying reader.
/// Invalidates all data in the internal buffer.
#[inline]
fn discard_buffer(&mut self) {
- self.pos = 0;
- self.cap = 0;
+ self.buf.discard_buffer()
}
}
/// must track this information themselves if it is required.
#[stable(feature = "bufreader_seek_relative", since = "1.53.0")]
pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
- let pos = self.pos as u64;
+ let pos = self.buf.pos() as u64;
if offset < 0 {
- if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
- self.pos = new_pos as usize;
+ if let Some(_) = pos.checked_sub((-offset) as u64) {
+ self.buf.unconsume((-offset) as usize);
return Ok(());
}
} else if let Some(new_pos) = pos.checked_add(offset as u64) {
- if new_pos <= self.cap as u64 {
- self.pos = new_pos as usize;
+ if new_pos <= self.buf.filled() as u64 {
+ self.buf.consume(offset as usize);
return Ok(());
}
}
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
// entirely.
- if self.pos == self.cap && buf.len() >= self.buf.len() {
+ if self.buf.pos() == self.buf.filled() && buf.len() >= self.capacity() {
self.discard_buffer();
return self.inner.read(buf);
}
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
// entirely.
- if self.pos == self.cap && buf.remaining() >= self.buf.len() {
+ if self.buf.pos() == self.buf.filled() && buf.remaining() >= self.capacity() {
self.discard_buffer();
return self.inner.read_buf(buf);
}
// generation for the common path where the buffer has enough bytes to fill the passed-in
// buffer.
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
- if self.buffer().len() >= buf.len() {
- buf.copy_from_slice(&self.buffer()[..buf.len()]);
- self.consume(buf.len());
+ if self.buf.consume_with(buf.len(), |claimed| buf.copy_from_slice(claimed)) {
return Ok(());
}
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
- if self.pos == self.cap && total_len >= self.buf.len() {
+ if self.buf.pos() == self.buf.filled() && total_len >= self.capacity() {
self.discard_buffer();
return self.inner.read_vectored(bufs);
}
// The inner reader might have an optimized `read_to_end`. Drain our buffer and then
// delegate to the inner implementation.
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- let nread = self.cap - self.pos;
- buf.extend_from_slice(&self.buffer());
+ let inner_buf = self.buffer();
+ buf.extend_from_slice(inner_buf);
+ let nread = inner_buf.len();
self.discard_buffer();
Ok(nread + self.inner.read_to_end(buf)?)
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read> BufRead for BufReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
- // If we've reached the end of our internal buffer then we need to fetch
- // some more data from the underlying reader.
- // Branch using `>=` instead of the more correct `==`
- // to tell the compiler that the pos..cap slice is always valid.
- if self.pos >= self.cap {
- debug_assert!(self.pos == self.cap);
-
- let mut readbuf = ReadBuf::uninit(&mut self.buf);
-
- // SAFETY: `self.init` is either 0 or set to `readbuf.initialized_len()`
- // from the last time this function was called
- unsafe {
- readbuf.assume_init(self.init);
- }
-
- self.inner.read_buf(&mut readbuf)?;
-
- self.cap = readbuf.filled_len();
- self.init = readbuf.initialized_len();
-
- self.pos = 0;
- }
- Ok(self.buffer())
+ self.buf.fill_buf(&mut self.inner)
}
fn consume(&mut self, amt: usize) {
- self.pos = cmp::min(self.pos + amt, self.cap);
+ self.buf.consume(amt)
}
}
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("BufReader")
.field("reader", &self.inner)
- .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()))
+ .field(
+ "buffer",
+ &format_args!("{}/{}", self.buf.filled() - self.buf.pos(), self.capacity()),
+ )
.finish()
}
}
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let result: u64;
if let SeekFrom::Current(n) = pos {
- let remainder = (self.cap - self.pos) as i64;
+ let remainder = (self.buf.filled() - self.buf.pos()) as i64;
// it should be safe to assume that remainder fits within an i64 as the alternative
// means we managed to allocate 8 exbibytes and that's absurd.
// But it's not out of the realm of possibility for some weird underlying reader to
/// }
/// ```
fn stream_position(&mut self) -> io::Result<u64> {
- let remainder = (self.cap - self.pos) as u64;
+ let remainder = (self.buf.filled() - self.buf.pos()) as u64;
self.inner.stream_position().map(|pos| {
pos.checked_sub(remainder).expect(
"overflow when subtracting remaining buffer size from inner stream position",
--- /dev/null
+///! An encapsulation of `BufReader`'s buffer management logic.
+///
+/// This module factors out the basic functionality of `BufReader` in order to protect two core
+/// invariants:
+/// * `filled` bytes of `buf` are always initialized
+/// * `pos` is always <= `filled`
+/// Since this module encapsulates the buffer management logic, we can ensure that the range
+/// `pos..filled` is always a valid index into the initialized region of the buffer. This means
+/// that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so
+/// without encountering any runtime bounds checks.
+use crate::cmp;
+use crate::io::{self, Read, ReadBuf};
+use crate::mem::MaybeUninit;
+
+pub struct Buffer {
+ // The buffer.
+ buf: Box<[MaybeUninit<u8>]>,
+ // The current seek offset into `buf`, must always be <= `filled`.
+ pos: usize,
+ // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are
+ // initialized with bytes from a read.
+ filled: usize,
+}
+
+impl Buffer {
+ #[inline]
+ pub fn with_capacity(capacity: usize) -> Self {
+ let buf = Box::new_uninit_slice(capacity);
+ Self { buf, pos: 0, filled: 0 }
+ }
+
+ #[inline]
+ pub fn buffer(&self) -> &[u8] {
+ // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and
+ // that region is initialized because those are all invariants of this type.
+ unsafe { MaybeUninit::slice_assume_init_ref(self.buf.get_unchecked(self.pos..self.filled)) }
+ }
+
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.buf.len()
+ }
+
+ #[inline]
+ pub fn filled(&self) -> usize {
+ self.filled
+ }
+
+ #[inline]
+ pub fn pos(&self) -> usize {
+ self.pos
+ }
+
+ #[inline]
+ pub fn discard_buffer(&mut self) {
+ self.pos = 0;
+ self.filled = 0;
+ }
+
+ #[inline]
+ pub fn consume(&mut self, amt: usize) {
+ self.pos = cmp::min(self.pos + amt, self.filled);
+ }
+
+ /// If there are `amt` bytes available in the buffer, pass a slice containing those bytes to
+ /// `visitor` and return true. If there are not enough bytes available, return false.
+ #[inline]
+ pub fn consume_with<V>(&mut self, amt: usize, mut visitor: V) -> bool
+ where
+ V: FnMut(&[u8]),
+ {
+ if let Some(claimed) = self.buffer().get(..amt) {
+ visitor(claimed);
+ // If the indexing into self.buffer() succeeds, amt must be a valid increment.
+ self.pos += amt;
+ true
+ } else {
+ false
+ }
+ }
+
+ #[inline]
+ pub fn unconsume(&mut self, amt: usize) {
+ self.pos = self.pos.saturating_sub(amt);
+ }
+
+ #[inline]
+ pub fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> {
+ // If we've reached the end of our internal buffer then we need to fetch
+ // some more data from the reader.
+ // Branch using `>=` instead of the more correct `==`
+ // to tell the compiler that the pos..cap slice is always valid.
+ if self.pos >= self.filled {
+ debug_assert!(self.pos == self.filled);
+
+ let mut readbuf = ReadBuf::uninit(&mut self.buf);
+
+ reader.read_buf(&mut readbuf)?;
+
+ self.filled = readbuf.filled_len();
+ self.pos = 0;
+ }
+ Ok(self.buffer())
+ }
+}
let mut buf = [0u8; 4];
for _ in 0..1024 {
reader.read_exact(&mut buf).unwrap();
+ core::hint::black_box(&buf);
}
});
}
/// use std::fs::File;
///
/// fn main() -> io::Result<()> {
- /// let mut f = File::open("foo.txt")?;
+ /// let f = File::open("foo.txt")?;
///
/// for byte in f.bytes() {
/// println!("{}", byte.unwrap());
/// use std::fs::File;
///
/// fn main() -> io::Result<()> {
- /// let mut f1 = File::open("foo.txt")?;
- /// let mut f2 = File::open("bar.txt")?;
+ /// let f1 = File::open("foo.txt")?;
+ /// let f2 = File::open("bar.txt")?;
///
/// let mut handle = f1.chain(f2);
/// let mut buffer = String::new();
/// use std::fs::File;
///
/// fn main() -> io::Result<()> {
- /// let mut f = File::open("foo.txt")?;
+ /// let f = File::open("foo.txt")?;
/// let mut buffer = [0; 5];
///
/// // read at most five bytes
let max = cmp::min(buf.len() as u64, self.limit) as usize;
let n = self.inner.read(&mut buf[..max])?;
+ assert!(n as u64 <= self.limit, "number of read bytes exceeds limit");
self.limit -= n as u64;
Ok(n)
}
}
}
+// Issue 94981
+#[test]
+#[should_panic = "number of read bytes exceeds limit"]
+fn test_take_wrong_length() {
+ struct LieAboutSize(bool);
+
+ impl Read for LieAboutSize {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ // Lie about the read size at first time of read.
+ if core::mem::take(&mut self.0) { Ok(buf.len() + 1) } else { Ok(buf.len()) }
+ }
+ }
+
+ let mut buffer = vec![0; 4];
+ let mut reader = LieAboutSize(true).take(4);
+ // Primed the `Limit` by lying about the read size.
+ let _ = reader.read(&mut buffer[..]);
+}
+
#[bench]
fn bench_take_read(b: &mut test::Bencher) {
b.iter(|| {
use crate::fs::{self, Metadata, OpenOptions};
use crate::io;
use crate::path::Path;
+use crate::sealed::Sealed;
use crate::sys;
use crate::sys_common::{AsInner, AsInnerMut};
/// Windows-specific extensions to [`fs::FileType`].
///
/// On Windows, a symbolic link knows whether it is a file or directory.
-#[unstable(feature = "windows_file_type_ext", issue = "none")]
-pub trait FileTypeExt {
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+pub trait FileTypeExt: Sealed {
/// Returns `true` if this file type is a symbolic link that is also a directory.
- #[unstable(feature = "windows_file_type_ext", issue = "none")]
+ #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
fn is_symlink_dir(&self) -> bool;
/// Returns `true` if this file type is a symbolic link that is also a file.
- #[unstable(feature = "windows_file_type_ext", issue = "none")]
+ #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
fn is_symlink_file(&self) -> bool;
}
-#[unstable(feature = "windows_file_type_ext", issue = "none")]
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+impl Sealed for fs::FileType {}
+
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
impl FileTypeExt for fs::FileType {
fn is_symlink_dir(&self) -> bool {
self.as_inner().is_symlink_dir()
pub mod sockets;
pub use self::fs::*;
-#[inline(always)]
-pub fn breakpoint_program_exited(tid: usize) {
- unsafe {
- match () {
- // SOLID_BP_PROGRAM_EXITED = 15
- #[cfg(target_arch = "arm")]
- () => core::arch::asm!("bkpt #15", in("r0") tid),
- #[cfg(target_arch = "aarch64")]
- () => core::arch::asm!("hlt #15", in("x0") tid),
- }
- }
-}
-
-#[inline(always)]
-pub fn breakpoint_abort() {
- unsafe {
- match () {
- // SOLID_BP_CSABORT = 16
- #[cfg(target_arch = "arm")]
- () => core::arch::asm!("bkpt #16"),
- #[cfg(target_arch = "aarch64")]
- () => core::arch::asm!("hlt #16"),
- }
- }
-}
-
// `solid_types.h`
pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID};
error::decode_error_kind(code)
}
-#[inline(always)]
+#[inline]
pub fn abort_internal() -> ! {
- loop {
- abi::breakpoint_abort();
- }
-}
-
-// This function is needed by the panic runtime. The symbol is named in
-// pre-link args for the target specification, so keep that in sync.
-#[cfg(not(test))]
-#[no_mangle]
-// NB. used by both libunwind and libpanic_abort
-pub extern "C" fn __rust_abort() {
- abort_internal();
+ unsafe { libc::abort() }
}
pub fn hashmap_random_keys() -> (u64, u64) {
use crate::sys_common::rwlock::StaticRwLock;
use crate::vec;
-use super::{abi, error, itron, memchr};
+use super::{error, itron, memchr};
// `solid` directly maps `errno`s to μITRON error codes.
impl itron::error::ItronError {
None
}
-pub fn exit(_code: i32) -> ! {
- let tid = itron::task::try_current_task_id().unwrap_or(0);
- loop {
- abi::breakpoint_program_exited(tid as usize);
- }
+pub fn exit(code: i32) -> ! {
+ rtabort!("exit({}) called", code);
}
pub fn getpid() -> u32 {
Some(PathBuf::from(OsString::from_vec(buf)))
}
+ #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
+ fn get_path(fd: c_int) -> Option<PathBuf> {
+ let info = Box::<libc::kinfo_file>::new_zeroed();
+ let mut info = unsafe { info.assume_init() };
+ info.kf_structsize = mem::size_of::<libc::kinfo_file>() as libc::c_int;
+ let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) };
+ if n == -1 {
+ return None;
+ }
+ let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() };
+ Some(PathBuf::from(OsString::from_vec(buf)))
+ }
+
#[cfg(target_os = "vxworks")]
fn get_path(fd: c_int) -> Option<PathBuf> {
let mut buf = vec![0; libc::PATH_MAX as usize];
target_os = "linux",
target_os = "macos",
target_os = "vxworks",
+ all(target_os = "freebsd", target_arch = "x86_64"),
target_os = "netbsd"
)))]
fn get_path(_fd: c_int) -> Option<PathBuf> {
panic!("Cannot use and generate PGO profiles at the same time");
}
+ // With LLD, we can use ICF (identical code folding) to reduce the executable size
+ // of librustc_driver/rustc and to improve i-cache utilization.
+ if builder.config.use_lld {
+ cargo.rustflag("-Clink-args=-Wl,--icf=all");
+ }
+
let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {
if compiler.stage == 1 {
cargo.rustflag(&format!("-Cprofile-generate={}", path));
impl Target {
pub fn from_triple(triple: &str) -> Self {
let mut target: Self = Default::default();
- if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") {
+ if triple.contains("-none")
+ || triple.contains("nvptx")
+ || triple.contains("switch")
+ || triple.contains("-uefi")
+ {
target.no_std = true;
}
target
--set target.x86_64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \
--set llvm.thin-lto=true \
--set llvm.ninja=false \
- --set rust.jemalloc
+ --set rust.jemalloc \
+ --set rust.use-lld=true
ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \
--host $HOSTS --target $HOSTS \
--include-default-paths \
$@ \
--rust-profile-use=${RUSTC_PROFILE_MERGED_FILE} \
--llvm-profile-use=${LLVM_PROFILE_MERGED_FILE}
+
+echo "Rustc binary size"
+ls -la ./build/$PGO_HOST/stage2/bin
+ls -la ./build/$PGO_HOST/stage2/lib
In the past the most common use case for customizing passes was to omit the `strip-private` pass.
You can do this more easily, and without risk of the pass being changed, by passing
-[`--document-private-items`](./unstable-features.md#--document-private-items).
+[`--document-private-items`](command-line-arguments.md#--document-private-items-show-items-that-are-not-public).
and is also accepted on stable toolchains.
It can also be used with `--show-coverage`. Take a look at its
-[documentation](#--show-coverage-get-statistics-about-code-documentation-coverage) for more
+[documentation](#--show-coverage-calculate-the-percentage-of-items-with-documentation) for more
information.
### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests
arrayvec = { version = "0.7", default-features = false }
askama = { version = "0.11", default-features = false, features = ["config"] }
atty = "0.2"
-pulldown-cmark = { version = "0.9", default-features = false }
+pulldown-cmark = { version = "0.9.2", default-features = false }
minifier = "0.2.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
let bound_predicate = self.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(pred) => bound_predicate.rebind(pred).clean(cx),
- ty::PredicateKind::RegionOutlives(pred) => pred.clean(cx),
- ty::PredicateKind::TypeOutlives(pred) => pred.clean(cx),
- ty::PredicateKind::Projection(pred) => Some(pred.clean(cx)),
+ ty::PredicateKind::Trait(pred) => {
+ clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
+ }
+ ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred, cx),
+ ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
+ ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
ty::PredicateKind::ConstEvaluatable(..) => None,
ty::PredicateKind::WellFormed(..) => None,
}
}
-impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::PolyTraitPredicate<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
- // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
- if self.skip_binder().constness == ty::BoundConstness::ConstIfConst
- && Some(self.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait()
- {
- return None;
- }
-
- let poly_trait_ref = self.map_bound(|pred| pred.trait_ref);
- Some(WherePredicate::BoundPredicate {
- ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
- bounds: vec![poly_trait_ref.clean(cx)],
- bound_params: Vec::new(),
- })
+fn clean_poly_trait_predicate<'tcx>(
+ pred: ty::PolyTraitPredicate<'tcx>,
+ cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+ // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
+ if pred.skip_binder().constness == ty::BoundConstness::ConstIfConst
+ && Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait()
+ {
+ return None;
}
-}
-impl<'tcx> Clean<'tcx, Option<WherePredicate>>
- for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
-{
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
- let ty::OutlivesPredicate(a, b) = self;
+ let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref);
+ Some(WherePredicate::BoundPredicate {
+ ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
+ bounds: vec![poly_trait_ref.clean(cx)],
+ bound_params: Vec::new(),
+ })
+}
- if a.is_empty() && b.is_empty() {
- return None;
- }
+fn clean_region_outlives_predicate<'tcx>(
+ pred: ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>,
+ cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+ let ty::OutlivesPredicate(a, b) = pred;
- Some(WherePredicate::RegionPredicate {
- lifetime: a.clean(cx).expect("failed to clean lifetime"),
- bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))],
- })
+ if a.is_empty() && b.is_empty() {
+ return None;
}
-}
-impl<'tcx> Clean<'tcx, Option<WherePredicate>>
- for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>
-{
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
- let ty::OutlivesPredicate(ty, lt) = self;
+ Some(WherePredicate::RegionPredicate {
+ lifetime: a.clean(cx).expect("failed to clean lifetime"),
+ bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))],
+ })
+}
- if lt.is_empty() {
- return None;
- }
+fn clean_type_outlives_predicate<'tcx>(
+ pred: ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>,
+ cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+ let ty::OutlivesPredicate(ty, lt) = pred;
- Some(WherePredicate::BoundPredicate {
- ty: clean_middle_ty(*ty, cx, None),
- bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
- bound_params: Vec::new(),
- })
+ if lt.is_empty() {
+ return None;
}
+
+ Some(WherePredicate::BoundPredicate {
+ ty: clean_middle_ty(ty, cx, None),
+ bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
+ bound_params: Vec::new(),
+ })
}
impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> {
}
}
-impl<'tcx> Clean<'tcx, WherePredicate> for ty::ProjectionPredicate<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> WherePredicate {
- let ty::ProjectionPredicate { projection_ty, term } = self;
- WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: term.clean(cx) }
+fn clean_projection_predicate<'tcx>(
+ pred: ty::ProjectionPredicate<'tcx>,
+ cx: &mut DocContext<'tcx>,
+) -> WherePredicate {
+ let ty::ProjectionPredicate { projection_ty, term } = pred;
+ WherePredicate::EqPredicate {
+ lhs: clean_projection(projection_ty, cx, None),
+ rhs: term.clean(cx),
}
}
}
}
-impl<'tcx> Clean<'tcx, Type> for ty::ProjectionTy<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Type {
- clean_projection(*self, cx, None)
- }
-}
-
fn compute_should_show_cast(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool {
!trait_.segments.is_empty()
&& self_def_id
.filter(|b| !b.is_sized_bound(cx)),
);
- let proj = projection
- .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term));
+ let proj = projection.map(|p| {
+ (
+ clean_projection(p.skip_binder().projection_ty, cx, None),
+ p.skip_binder().term,
+ )
+ });
if let Some(((_, trait_did, name), rhs)) = proj
.as_ref()
.and_then(|(lhs, rhs): &(Type, _)| Some((lhs.projection()?, rhs)))
ItemKind::Trait(_, _, generics, bounds, item_ids) => {
let items =
item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
+
TraitItem(Trait {
def_id,
items,
pub(crate) fn whole_name(&self) -> String {
self.segments
.iter()
- .map(|s| if s.name == kw::PathRoot { String::new() } else { s.name.to_string() })
- .intersperse("::".into())
+ .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
+ .intersperse("::")
.collect()
}
map.insert("synthetic-implementations-list".into(), 1);
map.insert("blanket-implementations-list".into(), 1);
map.insert("deref-methods".into(), 1);
+ map.insert("layout".into(), 1);
map
}
use clean::AttributesExt;
-use std::cmp::Ordering;
-use std::fmt;
-use std::rc::Rc;
-
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_target::abi::{Layout, Primitive, TagEncoding, Variants};
+use std::cmp::Ordering;
+use std::fmt;
+use std::rc::Rc;
use super::{
collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_section,
use crate::html::url_parts_builder::UrlPartsBuilder;
use askama::Template;
+use itertools::Itertools;
const ITEM_TABLE_OPEN: &str = "<div class=\"item-table\">";
const ITEM_TABLE_CLOSE: &str = "</div>";
let count_types = required_types.len() + provided_types.len();
let count_consts = required_consts.len() + provided_consts.len();
let count_methods = required_methods.len() + provided_methods.len();
+ let must_implement_one_of_functions =
+ cx.tcx().trait_def(t.def_id).must_implement_one_of.clone();
// Output the trait definition
wrap_into_docblock(w, |w| {
}
// Output the documentation for each function individually
- if !required_methods.is_empty() {
+ if !required_methods.is_empty() || must_implement_one_of_functions.is_some() {
write_small_section_header(
w,
"required-methods",
"Required Methods",
"<div class=\"methods\">",
);
+
+ if let Some(list) = must_implement_one_of_functions.as_deref() {
+ write!(
+ w,
+ "<div class=\"stab must_implement\">At least one of the `{}` methods is required.</div>",
+ list.iter().join("`, `")
+ );
+ }
+
for m in required_methods {
trait_item(w, cx, m, it);
}
return;
}
- writeln!(w, "<h2 class=\"small-section-header\">Layout</h2>");
+ writeln!(
+ w,
+ "<h2 id=\"layout\" class=\"small-section-header\"> \
+ Layout<a href=\"#layout\" class=\"anchor\"></a></h2>"
+ );
writeln!(w, "<div class=\"docblock\">");
let tcx = cx.tcx();
the sidebar stays visible for screen readers, which is useful for navigation. */
left: -1000px;
margin-left: 0;
- background-color: rgba(0,0,0,0);
margin: 0;
padding: 0;
z-index: 11;
/* Created this empty rule to satisfy the theme checks. */
.stab.empty-impl {}
+.stab.must_implement {}
.stab.unstable,
.stab.deprecated,
.stab.portability,
-.stab.empty-impl {
+.stab.empty-impl,
+.stab.must_implement {
color: #c5c5c5;
background: #314559 !important;
border-style: none !important;
.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
.stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; }
+.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
.stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
.stab.portability > code { background: none; }
.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; }
.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; }
+.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; }
.stab.portability { background: #F3DFFF; border-color: #b07bdb; }
.stab.portability > code { background: none; }
--- /dev/null
+// compile-flags: -O
+
+// Once we're done with llvm 14 and earlier, this test can be deleted.
+
+#![crate_type="lib"]
+
+use std::mem::MaybeUninit;
+
+// Boxing a `MaybeUninit` value should not copy junk from the stack
+#[no_mangle]
+pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
+ // CHECK-LABEL: @box_uninitialized
+ // CHECK-NOT: store
+ // CHECK-NOT: alloca
+ // CHECK-NOT: memcpy
+ // CHECK-NOT: memset
+ Box::new(MaybeUninit::uninit())
+}
+
+// FIXME: add a test for a bigger box. Currently broken, see
+// https://github.com/rust-lang/rust/issues/58201.
+
+// Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc
+// from the CHECK-NOT above. We don't check the attributes here because we can't rely
+// on all of them being set until LLVM 15.
+// CHECK: declare noalias{{.*}} @__rust_alloc(i{{[0-9]+}}, i{{[0-9]+.*}})
// compile-flags: -O
+// min-llvm-version: 15.0
#![crate_type="lib"]
use std::mem::MaybeUninit;
// FIXME: add a test for a bigger box. Currently broken, see
// https://github.com/rust-lang/rust/issues/58201.
+
+// Hide the `allocalign` attribute in the declaration of __rust_alloc
+// from the CHECK-NOT above, and also verify the attributes got set reasonably.
+// CHECK: declare noalias ptr @__rust_alloc(i{{[0-9]+}}, i{{[0-9]+}} allocalign) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]]
+
+// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} }
--- /dev/null
+// compile-flags: -O
+// only-x86_64
+// ignore-debug
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @vec_zero_bytes
+#[no_mangle]
+pub fn vec_zero_bytes(n: usize) -> Vec<u8> {
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc(
+ // CHECK-NOT: call {{.*}}llvm.memset
+
+ // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc(
+ // CHECK-NOT: call {{.*}}llvm.memset
+
+ // CHECK: ret void
+ vec![0; n]
+}
+
+// CHECK-LABEL: @vec_one_bytes
+#[no_mangle]
+pub fn vec_one_bytes(n: usize) -> Vec<u8> {
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+ // CHECK: call {{.*}}__rust_alloc(
+ // CHECK: call {{.*}}llvm.memset
+
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+ // CHECK: ret void
+ vec![1; n]
+}
+
+// CHECK-LABEL: @vec_zero_scalar
+#[no_mangle]
+pub fn vec_zero_scalar(n: usize) -> Vec<i32> {
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc(
+
+ // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc(
+
+ // CHECK: ret void
+ vec![0; n]
+}
+
+// CHECK-LABEL: @vec_one_scalar
+#[no_mangle]
+pub fn vec_one_scalar(n: usize) -> Vec<i32> {
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+ // CHECK: call {{.*}}__rust_alloc(
+
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+ // CHECK: ret void
+ vec![1; n]
+}
+
+// CHECK-LABEL: @vec_zero_rgb48
+#[no_mangle]
+pub fn vec_zero_rgb48(n: usize) -> Vec<[u16; 3]> {
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc(
+
+ // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc(
+
+ // CHECK: ret void
+ vec![[0, 0, 0]; n]
+}
+
+// CHECK-LABEL: @vec_zero_array_16
+#[no_mangle]
+pub fn vec_zero_array_16(n: usize) -> Vec<[i64; 16]> {
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc(
+
+ // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc(
+
+ // CHECK: ret void
+ vec![[0_i64; 16]; n]
+}
+
+// CHECK-LABEL: @vec_zero_tuple
+#[no_mangle]
+pub fn vec_zero_tuple(n: usize) -> Vec<(i16, u8, char)> {
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc(
+
+ // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc(
+
+ // CHECK: ret void
+ vec![(0, 0, '\0'); n]
+}
+
+// CHECK-LABEL: @vec_non_zero_tuple
+#[no_mangle]
+pub fn vec_non_zero_tuple(n: usize) -> Vec<(i16, u8, char)> {
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+ // CHECK: call {{.*}}__rust_alloc(
+
+ // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+ // CHECK-NOT: call {{.*}}reserve
+ // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+ // CHECK: ret void
+ vec![(0, 0, 'A'); n]
+}
// compile-flags: -O
// only-x86_64
// ignore-debug
+// min-llvm-version: 15.0
#![crate_type = "lib"]
// CHECK: ret void
vec![(0, 0, 'A'); n]
}
+
+// Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away.
+// CHECK: declare noalias ptr @__rust_alloc_zeroed(i64, i64 allocalign) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]]
+
+// CHECK-DAG: attributes [[RUST_ALLOC_ZEROED_ATTRS]] = { {{.*}} allockind("alloc,zeroed,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} }
--- /dev/null
+#![feature(adt_const_params)]
+#![allow(incomplete_features)]
+
+pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
+ BYTES
+}
+
+// EMIT_MIR issue_99325.main.mir_map.0.mir
+pub fn main() {
+ assert_eq!(function_with_bytes::<b"AAAA">(), &[0x41, 0x41, 0x41, 0x41]);
+ assert_eq!(function_with_bytes::<{ &[0x41, 0x41, 0x41, 0x41] }>(), b"AAAA");
+}
--- /dev/null
+// MIR for `main` 0 mir_map
+
+| User Type Annotations
+| 0: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Value(Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)])) }], user_self_ty: None }) }, span: $DIR/issue-99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:8 ~ issue_99325[8f58]::main::{constant#1}), const_param_did: Some(DefId(0:4 ~ issue_99325[8f58]::function_with_bytes::BYTES)) }, substs: [], promoted: None }) }], user_self_ty: None }) }, span: $DIR/issue-99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+|
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue-99325.rs:9:15: 9:15
+ let _1: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _2: (&&[u8], &&[u8; 4]); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _3: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _4: &[u8]; // in scope 0 at $DIR/issue-99325.rs:10:16: 10:48
+ let mut _5: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _6: &[u8; 4]; // in scope 0 at $DIR/issue-99325.rs:10:50: 10:75
+ let _7: [u8; 4]; // in scope 0 at $DIR/issue-99325.rs:10:51: 10:75
+ let _8: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _9: &&[u8; 4]; // 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: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _13: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _14: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _16: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _17: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _18: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _19: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _20: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _21: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _22: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _23: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _24: (&&[u8], &&[u8; 4]); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _25: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _26: &[u8]; // in scope 0 at $DIR/issue-99325.rs:11:16: 11:70
+ let mut _27: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _28: &[u8; 4]; // in scope 0 at $DIR/issue-99325.rs:11:72: 11:79
+ let _29: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _30: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _31: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _32: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _33: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _34: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _35: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _37: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _38: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _39: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _40: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _41: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _42: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _43: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 1 {
+ debug left_val => _8; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug right_val => _9; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _15: core::panicking::AssertKind; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 2 {
+ debug kind => _15; // in scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+ }
+ scope 3 {
+ debug left_val => _29; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug right_val => _30; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _36: core::panicking::AssertKind; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 4 {
+ debug kind => _36; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_4); // scope 0 at $DIR/issue-99325.rs:10:16: 10:48
+ _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb19]; // scope 0 at $DIR/issue-99325.rs:10:16: 10:48
+ // mir::Constant
+ // + span: $DIR/issue-99325.rs:10:16: 10:46
+ // + user_ty: UserType(0)
+ // + literal: Const { ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ _3 = &_4; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_5); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_6); // scope 0 at $DIR/issue-99325.rs:10:50: 10:75
+ StorageLive(_7); // scope 0 at $DIR/issue-99325.rs:10:51: 10:75
+ _7 = [const 65_u8, const 65_u8, const 65_u8, const 65_u8]; // scope 0 at $DIR/issue-99325.rs:10:51: 10:75
+ _6 = &_7; // scope 0 at $DIR/issue-99325.rs:10:50: 10:75
+ _5 = &_6; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _2 = (move _3, move _5); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_5); // 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
+ FakeRead(ForMatchedPlace(None), _2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_8); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _8 = (_2.0: &&[u8]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_9); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _9 = (_2.1: &&[u8; 4]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_10); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_12); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _12 = &(*_8); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_13); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _13 = &(*_9); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _11 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _12, move _13) -> [return: bb2, unwind: bb19]; // scope 1 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> fn(&'r &[u8], &'s &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ StorageDead(_13); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_12); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _10 = Not(move _11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ switchInt(move _10) -> [false: bb4, otherwise: bb3]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb3: {
+ StorageLive(_15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _15 = core::panicking::AssertKind::Eq; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ FakeRead(ForLet(None), _15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_16); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_17); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _17 = move _15; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_18); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _19 = &(*_8); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _18 = &(*_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_20); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _21 = &(*_9); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _20 = &(*_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_22); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _22 = Option::<Arguments>::None; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _16 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _17, move _18, move _20, move _22) -> bb19; // scope 2 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 &[u8], &'s &[u8; 4], Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
+ }
+
+ bb4: {
+ goto -> bb7; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb5: {
+ StorageDead(_22); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_20); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_18); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_17); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_16); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ unreachable; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb6: {
+ goto -> bb8; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb7: {
+ _1 = const (); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ goto -> bb8; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb8: {
+ StorageDead(_10); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_9); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_8); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ goto -> bb9; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb9: {
+ StorageDead(_7); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_6); // 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
+ StorageDead(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_1); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_23); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_25); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_26); // scope 0 at $DIR/issue-99325.rs:11:16: 11:70
+ _26 = function_with_bytes::<&*b"AAAA">() -> [return: bb10, unwind: bb19]; // scope 0 at $DIR/issue-99325.rs:11:16: 11:70
+ // mir::Constant
+ // + span: $DIR/issue-99325.rs:11:16: 11:68
+ // + user_ty: UserType(1)
+ // + literal: Const { ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}, val: Value(<ZST>) }
+ }
+
+ bb10: {
+ _25 = &_26; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_28); // scope 0 at $DIR/issue-99325.rs:11:72: 11:79
+ _28 = const b"AAAA"; // scope 0 at $DIR/issue-99325.rs:11:72: 11:79
+ // mir::Constant
+ // + span: $DIR/issue-99325.rs:11:72: 11:79
+ // + literal: Const { ty: &[u8; 4], val: Value(Scalar(alloc4)) }
+ _27 = &_28; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _24 = (move _25, move _27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_25); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ FakeRead(ForMatchedPlace(None), _24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_29); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _29 = (_24.0: &&[u8]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_30); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _30 = (_24.1: &&[u8; 4]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_31); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_33); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _33 = &(*_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_34); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _34 = &(*_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _32 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _33, move _34) -> [return: bb11, unwind: bb19]; // 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: for<'r, 's> fn(&'r &[u8], &'s &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
+ }
+
+ bb11: {
+ StorageDead(_34); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_33); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _31 = Not(move _32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ switchInt(move _31) -> [false: bb13, otherwise: bb12]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb12: {
+ StorageLive(_36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _36 = core::panicking::AssertKind::Eq; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ FakeRead(ForLet(None), _36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_37); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_38); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _38 = move _36; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_39); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _40 = &(*_29); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _39 = &(*_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_41); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _42 = &(*_30); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _41 = &(*_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_43); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _43 = Option::<Arguments>::None; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _37 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _38, move _39, move _41, move _43) -> bb19; // scope 4 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 &[u8], &'s &[u8; 4], Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
+ }
+
+ bb13: {
+ goto -> bb16; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb14: {
+ StorageDead(_43); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_41); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_39); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_38); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_37); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ unreachable; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb15: {
+ goto -> bb17; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb16: {
+ _23 = const (); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ goto -> bb17; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb17: {
+ StorageDead(_31); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_30); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_29); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ goto -> bb18; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb18: {
+ StorageDead(_28); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_26); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_23); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _0 = const (); // scope 0 at $DIR/issue-99325.rs:9:15: 12:2
+ return; // scope 0 at $DIR/issue-99325.rs:12:2: 12:2
+ }
+
+ bb19 (cleanup): {
+ resume; // scope 0 at $DIR/issue-99325.rs:9:1: 12:2
+ }
+}
+
+alloc4 (size: 4, align: 1) {
+ 41 41 41 41 │ AAAA
+}
1| |// Regression test for issue #98833.
- 2| |// compile-flags: -Zinline-mir
+ 2| |// compile-flags: -Zinline-mir -Cdebug-assertions=off
3| |
4| 1|fn main() {
5| 1| println!("{}", live::<false>());
- 6| 1|}
- 7| |
- 8| |#[inline]
- 9| 1|fn live<const B: bool>() -> u32 {
- 10| 1| if B {
- 11| 0| dead()
- 12| | } else {
- 13| 1| 0
- 14| | }
- 15| 1|}
- 16| |
- 17| |#[inline]
- 18| 0|fn dead() -> u32 {
- 19| 0| 42
- 20| 0|}
+ 6| 1|
+ 7| 1| let f = |x: bool| {
+ 8| | debug_assert!(
+ 9| | x
+ 10| | );
+ 11| 1| };
+ 12| 1| f(false);
+ 13| 1|}
+ 14| |
+ 15| |#[inline]
+ 16| 1|fn live<const B: bool>() -> u32 {
+ 17| 1| if B {
+ 18| 0| dead()
+ 19| | } else {
+ 20| 1| 0
+ 21| | }
+ 22| 1|}
+ 23| |
+ 24| |#[inline]
+ 25| 0|fn dead() -> u32 {
+ 26| 0| 42
+ 27| 0|}
// Regression test for issue #98833.
-// compile-flags: -Zinline-mir
+// compile-flags: -Zinline-mir -Cdebug-assertions=off
fn main() {
println!("{}", live::<false>());
+
+ let f = |x: bool| {
+ debug_assert!(
+ x
+ );
+ };
+ f(false);
}
#[inline]
OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
-Fo:`cygpath -w $(TMPDIR)/$(1).obj`
else
-COMPILE_OBJ = $(CC) -c -o $(1) $(2)
+COMPILE_OBJ = $(CC) -v -c -o $(1) $(2)
COMPILE_OBJ_CXX = $(CXX) -c -o $(1) $(2)
NATIVE_STATICLIB_FILE = lib$(1).a
NATIVE_STATICLIB = $(call STATICLIB,$(1))
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+# ignore-wasm32
+# ignore-wasm64
+# ignore-none no-std is not supported
+# only-linux
+
+all:
+ $(RUSTC) -Zexport-executable-symbols main.rs --target $(TARGET) --crate-type=bin
+ nm $(TMPDIR)/main | $(CGREP) exported_symbol
+
--- /dev/null
+// edition:2018
+
+fn main() {}
+
+#[no_mangle]
+pub fn exported_symbol() -> i8 {
+ 42
+}
-include ../../run-make-fulldeps/tools.mk
all:
+ $(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
+ $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
$(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
ifdef IS_MSVC
- $(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll
+ $(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll -noimplib
else
$(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
endif
- $(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
- $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
ifdef RUSTC_BLESS_TEST
-include ../../run-make-fulldeps/tools.mk
all:
+ $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+ $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
+ $(RUSTC) --crate-type bin --crate-name raw_dylib_test_bin lib.rs
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
ifdef IS_MSVC
- $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll
- $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll
+ $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib
+ $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib
else
$(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
endif
- $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
- $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
+ "$(TMPDIR)"/raw_dylib_test_bin > "$(TMPDIR)"/output_bin.txt
ifdef RUSTC_BLESS_TEST
cp "$(TMPDIR)"/output.txt output.txt
else
$(DIFF) output.txt "$(TMPDIR)"/output.txt
+ $(DIFF) output.txt "$(TMPDIR)"/output_bin.txt
endif
extern_fn_3();
}
}
+
+fn main() {
+ library_function();
+}
-include ../../run-make-fulldeps/tools.mk
all:
+ $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+ $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
$(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
ifdef IS_MSVC
- $(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll
+ $(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll -noimplib
else
$(CC) "$(TMPDIR)"/exporter.obj exporter.def -shared -o "$(TMPDIR)"/exporter.dll
endif
- $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
- $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
ifdef RUSTC_BLESS_TEST
-include ../../run-make-fulldeps/tools.mk
all:
+ $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+ $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
$(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
ifdef IS_MSVC
- $(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll
+ $(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll -noimplib
else
$(CC) "$(TMPDIR)"/exporter.obj exporter-gnu.def -shared -o "$(TMPDIR)"/exporter.dll
endif
- $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
- $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
"$(TMPDIR)"/driver > "$(TMPDIR)"/actual_output.txt
ifdef RUSTC_BLESS_TEST
click: ".sidebar-menu-toggle"
scroll-to: ".block.keyword li:nth-child(1)"
compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543})
+
+// Now checking the background color of the sidebar.
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
+reload:
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"background-color": "rgb(80, 80, 80)"})
+
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "ayu"}
+reload:
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"background-color": "rgb(20, 25, 31)"})
+
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "light"}
+reload:
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"background-color": "rgb(245, 245, 245)"})
-Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
-Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
-Z emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes)
+ -Z export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries
-Z fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
-Z force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
-Z fuel=val -- set the optimization fuel quota for a crate
--- /dev/null
+#![crate_name = "c"]
+#![feature(rustc_attrs)]
+
+#[rustc_must_implement_one_of(a, b)]
+// @matches c/trait.Trait.html '//*[@class="stab must_implement"]' \
+// 'At least one of the `a`, `b` methods is required.$'
+pub trait Trait {
+ fn a() {}
+ fn b() {}
+}
// @has type_layout/struct.Foo.html 'Size: '
// @has - ' bytes'
+// @has - '//*[@id="layout"]/a[@href="#layout"]' ''
pub struct Foo {
pub a: usize,
b: Vec<String>,
LL | #[rustc_lint_diagnostics(a)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_lint_diagnostics]`
-error: attribute should be applied to a function
+error: attribute should be applied to a function definition
--> $DIR/diagnostics_incorrect.rs:5:1
|
LL | #[rustc_lint_diagnostics]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | struct Foo;
- | ----------- not a function
+ | ----------- not a function definition
error: aborting due to 2 previous errors
LL | #[rustc_lint_query_instability(a)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_lint_query_instability]`
-error: attribute should be applied to a function
+error: attribute should be applied to a function definition
--> $DIR/query_stability_incorrect.rs:5:1
|
LL | #[rustc_lint_query_instability]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | struct Foo;
- | ----------- not a function
+ | ----------- not a function definition
error: aborting due to 2 previous errors
impl<'a> Foo for &'a () {
const NAME: &'a str = "unit";
- //~^ ERROR mismatched types [E0308]
+ //~^ ERROR const not compatible with trait
}
fn main() {}
-error[E0308]: mismatched types
+error[E0308]: const not compatible with trait
--> $DIR/associated-const-impl-wrong-lifetime.rs:7:5
|
LL | const NAME: &'a str = "unit";
--- /dev/null
+#![feature(associated_type_bounds)]
+#![feature(anonymous_lifetime_in_impl_trait)]
+
+// The same thing should happen for constaints in dyn trait.
+fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
+//~^ ERROR missing lifetime specifier
+//~| ERROR mismatched types
+
+fn main() {}
--- /dev/null
+error[E0106]: missing lifetime specifier
+ --> $DIR/elision.rs:5:70
+ |
+LL | fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
+ | ------------------------------------------------ ^^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of `x`'s 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+ |
+LL | fn f<'a>(x: &'a mut dyn Iterator<Item: Iterator<Item = &'a ()>>) -> Option<&'a ()> { x.next() }
+ | ++++ ++ ~~ ~~
+
+error[E0308]: mismatched types
+ --> $DIR/elision.rs:5:79
+ |
+LL | fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
+ | ----------------------------- -------------- ^^^^^^^^ expected `&()`, found type parameter `impl Iterator<Item = &'_ ()>`
+ | | |
+ | | expected `Option<&'static ()>` because of return type
+ | this type parameter
+ |
+ = note: expected enum `Option<&'static ()>`
+ found enum `Option<impl Iterator<Item = &'_ ()>>`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0106, E0308.
+For more information about an error, try `rustc --explain E0106`.
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
- = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider making the bound lifetime-generic with a new `'a` lifetime
- |
-LL | fn elision<T: for<'a> Fn() -> &'a i32>() {
- | +++++++ ~~~
help: consider using the `'static` lifetime
|
LL | fn elision<T: Fn() -> &'static i32>() {
- | ~~~~~~~~
+ | +++++++
error: aborting due to previous error
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
- = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider making the type lifetime-generic with a new `'a` lifetime
- |
-LL | fn elision(_: for<'a> fn() -> &'a i32) {
- | +++++++ ~~~
help: consider using the `'static` lifetime
|
LL | fn elision(_: fn() -> &'static i32) {
- | ~~~~~~~~
+ | +++++++
error: aborting due to previous error
foo: &dyn Foo, bar: &'a dyn Foo
) -> &dyn Foo //~ ERROR missing lifetime specifier
{
+ //~^ ERROR explicit lifetime required in the type of `foo` [E0621]
foo
}
}
help: consider using the `'a` lifetime
|
LL | ) -> &'a dyn Foo
- | ~~~
+ | ++
-error: aborting due to previous error
+error[E0621]: explicit lifetime required in the type of `foo`
+ --> $DIR/issue-63388-2.rs:13:5
+ |
+LL | foo: &dyn Foo, bar: &'a dyn Foo
+ | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)`
+LL | ) -> &dyn Foo
+LL | / {
+LL | |
+LL | | foo
+LL | | }
+ | |_____^ lifetime `'a` required
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0106, E0621.
+For more information about an error, try `rustc --explain E0106`.
|
= help: consider adding the following bound: `'a: 'b`
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Trait<'a>` captures lifetime that does not appear in bounds
--> $DIR/ret-impl-trait-one.rs:16:80
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
LL | ) -> &usize {
| ^ expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
LL | ) -> &'static usize {
- | ~~~~~~~~
+ | +++++++
error: aborting due to previous error
--- /dev/null
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+struct Outer<T: ?Sized> {
+ i: InnerSend<T>,
+}
+
+type InnerSend<T: ?Sized> = impl Send;
+
+fn constrain<T: ?Sized>() -> InnerSend<T> {
+ ()
+}
+
+trait SendMustNotImplDrop {}
+
+#[allow(drop_bounds)]
+impl<T: ?Sized + Send + Drop> SendMustNotImplDrop for T {}
+
+impl<T: ?Sized> SendMustNotImplDrop for Outer<T> {}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+struct Send<T> {
+ i: InnerSend<T>,
+}
+
+type InnerSend<T> = impl Sized;
+
+fn constrain<T>() -> InnerSend<T> {
+ ()
+}
+
+trait SendMustNotImplDrop {}
+
+#[allow(drop_bounds)]
+impl<T: Drop> SendMustNotImplDrop for T {}
+
+impl<T> SendMustNotImplDrop for Send<T> {}
+
+fn main() {}
+// check-pass
+
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
}
fn main() {
- // FIXME(generic_const_exprs): We can't correctly infer `T` which requires
- // evaluating `{ N + 1 }` which has substs containing an inference var
let mut _q = Default::default();
- //~^ ERROR type annotations needed
-
_q = foo::<_, 2>(_q);
- //~^ ERROR type annotations needed
}
+++ /dev/null
-error[E0282]: type annotations needed
- --> $DIR/const_eval_resolve_canonical.rs:26:9
- |
-LL | let mut _q = Default::default();
- | ^^^^^^
- |
-help: consider giving `_q` an explicit type
- |
-LL | let mut _q: _ = Default::default();
- | +++
-
-error[E0283]: type annotations needed
- --> $DIR/const_eval_resolve_canonical.rs:29:10
- |
-LL | _q = foo::<_, 2>(_q);
- | ^^^^^^^^^^^ cannot infer the value of the constant `{ N + 1 }`
- |
-note: multiple `impl`s satisfying `(): Foo<{ N + 1 }>` found
- --> $DIR/const_eval_resolve_canonical.rs:8:1
- |
-LL | impl Foo<0> for () {
- | ^^^^^^^^^^^^^^^^^^
-...
-LL | impl Foo<3> for () {
- | ^^^^^^^^^^^^^^^^^^
-note: required by a bound in `foo`
- --> $DIR/const_eval_resolve_canonical.rs:18:9
- |
-LL | fn foo<T, const N: usize>(_: T) -> <() as Foo<{ N + 1 }>>::Assoc
- | --- required by a bound in this
-LL | where
-LL | (): Foo<{ N + 1 }>,
- | ^^^^^^^^^^^^^^ required by this bound in `foo`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0282, E0283.
-For more information about an error, try `rustc --explain E0282`.
fn consume<T: 'static>(_val: T)
where
If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
- //~^ ERROR: overly complex generic constant
- //~| ERROR: cannot call non-const operator in constants
+ //~^ ERROR: can't compare
{
}
fn test<T: 'static>()
where
If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
- //~^ ERROR: overly complex generic constant
- //~| ERROR: cannot call non-const operator in constants
+ //~^ ERROR: can't compare
{
}
-error: overly complex generic constant
- --> $DIR/issue-90318.rs:14:8
+error[E0277]: can't compare `TypeId` with `_` in const contexts
+ --> $DIR/issue-90318.rs:14:28
|
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
- | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | borrowing is not supported in generic constants
+ | ^^ no implementation for `TypeId == _`
|
- = help: consider moving this anonymous constant into a `const` function
- = note: this operation may be supported in the future
-
-error[E0015]: cannot call non-const operator in constants
- --> $DIR/issue-90318.rs:14:10
+ = help: the trait `~const PartialEq<_>` is not implemented for `TypeId`
+note: the trait `PartialEq<_>` is implemented for `TypeId`, but that implementation is not `const`
+ --> $DIR/issue-90318.rs:14:28
|
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: impl defined here, but it is not `const`
- --> $SRC_DIR/core/src/any.rs:LL:COL
- |
-LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
- | ^^^^^^^^^
- = note: calls in constants are limited to constant functions, tuple structs and tuple variants
- = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+ | ^^
-error: overly complex generic constant
- --> $DIR/issue-90318.rs:22:8
+error[E0277]: can't compare `TypeId` with `_` in const contexts
+ --> $DIR/issue-90318.rs:21:28
|
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
- | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | borrowing is not supported in generic constants
+ | ^^ no implementation for `TypeId == _`
|
- = help: consider moving this anonymous constant into a `const` function
- = note: this operation may be supported in the future
-
-error[E0015]: cannot call non-const operator in constants
- --> $DIR/issue-90318.rs:22:10
+ = help: the trait `~const PartialEq<_>` is not implemented for `TypeId`
+note: the trait `PartialEq<_>` is implemented for `TypeId`, but that implementation is not `const`
+ --> $DIR/issue-90318.rs:21:28
|
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: impl defined here, but it is not `const`
- --> $SRC_DIR/core/src/any.rs:LL:COL
- |
-LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
- | ^^^^^^^^^
- = note: calls in constants are limited to constant functions, tuple structs and tuple variants
- = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+ | ^^
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0277`.
LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
- | ptr_offset_from_unsigned called on pointers into different allocations
+ | `ptr_offset_from_unsigned` called on pointers into different allocations
| inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
- | ptr_offset_from_unsigned called on pointers into different allocations
+ | `ptr_offset_from_unsigned` called on pointers into different allocations
| inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
- | ptr_offset_from_unsigned called on pointers into different allocations
+ | `ptr_offset_from_unsigned` called on pointers into different allocations
| inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
- | ptr_offset_from_unsigned called on pointers into different allocations
+ | `ptr_offset_from_unsigned` called on pointers into different allocations
| inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
fn main() {}
// unconst and bad, will thus error in miri
-const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably
+const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR can't compare
// unconst and bad, will thus error in miri
-const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably
+const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR can't compare
-error: pointers cannot be reliably compared during const eval
- --> $DIR/const_raw_ptr_ops.rs:4:26
+error[E0277]: can't compare `*const i32` with `_` in const contexts
+ --> $DIR/const_raw_ptr_ops.rs:4:43
|
LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^ no implementation for `*const i32 == _`
|
- = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+ = help: the trait `~const PartialEq<_>` is not implemented for `*const i32`
+note: the trait `PartialEq<_>` is implemented for `*const i32`, but that implementation is not `const`
+ --> $DIR/const_raw_ptr_ops.rs:4:43
+ |
+LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
+ | ^^
+ = help: the following other types implement trait `PartialEq<Rhs>`:
+ f32
+ f64
+ i128
+ i16
+ i32
+ i64
+ i8
+ isize
+ and 6 others
-error: pointers cannot be reliably compared during const eval
- --> $DIR/const_raw_ptr_ops.rs:6:27
+error[E0277]: can't compare `*const i32` with `_` in const contexts
+ --> $DIR/const_raw_ptr_ops.rs:6:44
|
LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^ no implementation for `*const i32 == _`
|
- = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+ = help: the trait `~const PartialEq<_>` is not implemented for `*const i32`
+note: the trait `PartialEq<_>` is implemented for `*const i32`, but that implementation is not `const`
+ --> $DIR/const_raw_ptr_ops.rs:6:44
+ |
+LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
+ | ^^
+ = help: the following other types implement trait `PartialEq<Rhs>`:
+ f32
+ f64
+ i128
+ i16
+ i32
+ i64
+ i8
+ isize
+ and 6 others
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0277`.
fn id<T>(t: T) -> T { t }
fn main() {
const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
- //~^ ERROR pointers cannot be reliably compared during const eval
+ //~^ ERROR can't compare
println!("{}", A);
}
-error: pointers cannot be reliably compared during const eval
- --> $DIR/issue-25826.rs:3:30
+error[E0277]: can't compare `*const ()` with `*const ()` in const contexts
+ --> $DIR/issue-25826.rs:3:52
|
LL | const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^ no implementation for `*const () < *const ()` and `*const () > *const ()`
|
- = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+ = help: the trait `~const PartialOrd` is not implemented for `*const ()`
+note: the trait `PartialOrd` is implemented for `*const ()`, but that implementation is not `const`
+ --> $DIR/issue-25826.rs:3:52
+ |
+LL | const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
+ | ^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+ |
+LL | fn main() where *const (): ~const PartialOrd {
+ | ++++++++++++++++++++++++++++++++++
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0277`.
const fn cmp(x: fn(), y: fn()) -> bool {
unsafe { x == y }
- //~^ ERROR pointers cannot be reliably compared
+ //~^ ERROR can't compare
}
fn main() {}
-error: pointers cannot be reliably compared during const eval
- --> $DIR/cmp_fn_pointers.rs:2:14
+error[E0277]: can't compare `fn()` with `_` in const contexts
+ --> $DIR/cmp_fn_pointers.rs:2:16
|
LL | unsafe { x == y }
- | ^^^^^^
+ | ^^ no implementation for `fn() == _`
|
- = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+ = help: the trait `~const PartialEq<_>` is not implemented for `fn()`
+note: the trait `PartialEq<_>` is implemented for `fn()`, but that implementation is not `const`
+ --> $DIR/cmp_fn_pointers.rs:2:16
+ |
+LL | unsafe { x == y }
+ | ^^
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0277`.
#![feature(core_intrinsics)]
#![allow(const_err)]
-// During CTFE, we prevent pointer comparison and pointer-to-int casts.
-
-static CMP: () = {
- let x = &0 as *const _;
- let _v = x == x;
- //~^ ERROR could not evaluate static initializer
- //~| "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
-};
+// During CTFE, we prevent pointer-to-int casts.
+// Pointer comparisons are prevented in the trait system.
static PTR_INT_CAST: () = {
let x = &0 as *const _ as usize;
error[E0080]: could not evaluate static initializer
- --> $DIR/ptr_arith.rs:9:14
- |
-LL | let _v = x == x;
- | ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
-
-error[E0080]: could not evaluate static initializer
- --> $DIR/ptr_arith.rs:15:13
+ --> $DIR/ptr_arith.rs:9:13
|
LL | let x = &0 as *const _ as usize;
| ^^^^^^^^^^^^^^^^^^^^^^^ "exposing pointers" needs an rfc before being allowed inside constants
error[E0080]: could not evaluate static initializer
- --> $DIR/ptr_arith.rs:23:14
+ --> $DIR/ptr_arith.rs:17:14
|
LL | let _v = x + 0;
| ^ unable to turn pointer into raw bytes
warning: skipping const checks
|
help: skipping check that does not even have a feature gate
- --> $DIR/ptr_arith.rs:9:14
- |
-LL | let _v = x == x;
- | ^^^^^^
-help: skipping check that does not even have a feature gate
- --> $DIR/ptr_arith.rs:15:13
+ --> $DIR/ptr_arith.rs:9:13
|
LL | let x = &0 as *const _ as usize;
| ^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0080`.
#![feature(core_intrinsics)]
use std::intrinsics::{ptr_offset_from, ptr_offset_from_unsigned};
+use std::ptr;
#[repr(C)]
struct Struct {
let base_ptr: *const Struct = &uninit as *const _ as *const Struct;
let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
- let offset = unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }; //~ERROR evaluation of constant value failed
+ unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } //~ERROR evaluation of constant value failed
//~| pointers into different allocations
- offset as usize
+};
+
+pub const TOO_FAR_APART1: isize = {
+ let ptr1 = ptr::null::<u8>();
+ let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
+ unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed
+ //~| too far ahead
+};
+pub const TOO_FAR_APART2: isize = {
+ let ptr1 = ptr::null::<u8>();
+ let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
+ unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed
+ //~| too far before
};
const WRONG_ORDER_UNSIGNED: usize = {
unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } //~ERROR evaluation of constant value failed
//~| first pointer has smaller offset than second: 0 < 8
};
+pub const TOO_FAR_APART_UNSIGNED: usize = {
+ let ptr1 = ptr::null::<u8>();
+ let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
+ // This would fit into a `usize` but we still don't allow it.
+ unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } //~ERROR evaluation of constant value failed
+ //~| too far ahead
+};
+
+// These do NOT complain that pointers are too far apart; they pass that check (to then fail the
+// next one).
+pub const OFFSET_VERY_FAR1: isize = {
+ let ptr1 = ptr::null::<u8>();
+ let ptr2 = ptr1.wrapping_offset(isize::MAX);
+ unsafe { ptr2.offset_from(ptr1) }
+ //~^ inside
+};
+pub const OFFSET_VERY_FAR2: isize = {
+ let ptr1 = ptr::null::<u8>();
+ let ptr2 = ptr1.wrapping_offset(isize::MAX);
+ unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) }
+ //~^ inside
+};
fn main() {}
error[E0080]: evaluation of constant value failed
- --> $DIR/offset_from_ub.rs:17:27
+ --> $DIR/offset_from_ub.rs:18:27
|
LL | let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from called on pointers into different allocations
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on pointers into different allocations
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
LL | unsafe { intrinsics::ptr_offset_from(self, origin) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
- | ptr_offset_from called on pointers into different allocations
+ | `ptr_offset_from` called on pointers into different allocations
| inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
- ::: $DIR/offset_from_ub.rs:23:14
+ ::: $DIR/offset_from_ub.rs:24:14
|
LL | unsafe { (42 as *const u8).offset_from(&5u8) as usize }
- | ----------------------------------- inside `NOT_PTR` at $DIR/offset_from_ub.rs:23:14
+ | ----------------------------------- inside `NOT_PTR` at $DIR/offset_from_ub.rs:24:14
error[E0080]: evaluation of constant value failed
- --> $DIR/offset_from_ub.rs:30:14
+ --> $DIR/offset_from_ub.rs:31:14
|
LL | unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder
error[E0080]: evaluation of constant value failed
- --> $DIR/offset_from_ub.rs:36:14
+ --> $DIR/offset_from_ub.rs:37:14
|
LL | unsafe { ptr_offset_from(ptr, ptr) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
error[E0080]: evaluation of constant value failed
- --> $DIR/offset_from_ub.rs:43:14
+ --> $DIR/offset_from_ub.rs:44:14
|
LL | unsafe { ptr_offset_from(ptr2, ptr1) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x8[noalloc] is a dangling pointer (it has no provenance)
error[E0080]: evaluation of constant value failed
- --> $DIR/offset_from_ub.rs:52:14
+ --> $DIR/offset_from_ub.rs:53:14
|
LL | unsafe { ptr_offset_from(end_ptr, start_ptr) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
error[E0080]: evaluation of constant value failed
- --> $DIR/offset_from_ub.rs:61:14
+ --> $DIR/offset_from_ub.rs:62:14
|
LL | unsafe { ptr_offset_from(start_ptr, end_ptr) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
error[E0080]: evaluation of constant value failed
- --> $DIR/offset_from_ub.rs:69:14
+ --> $DIR/offset_from_ub.rs:70:14
|
LL | unsafe { ptr_offset_from(end_ptr, end_ptr) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds
error[E0080]: evaluation of constant value failed
- --> $DIR/offset_from_ub.rs:78:27
+ --> $DIR/offset_from_ub.rs:79:14
|
-LL | let offset = unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called on pointers into different allocations
+LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:86:14
|
+LL | unsafe { ptr_offset_from(ptr2, ptr1) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far ahead of second
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/offset_from_ub.rs:92:14
+ |
+LL | unsafe { ptr_offset_from(ptr1, ptr2) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/offset_from_ub.rs:99:14
+ |
LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 8
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/offset_from_ub.rs:106:14
+ |
+LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second
+
+error[E0080]: evaluation of constant value failed
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::ptr_offset_from(self, origin) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
+ | inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $DIR/offset_from_ub.rs:115:14
+ |
+LL | unsafe { ptr2.offset_from(ptr1) }
+ | ---------------------- inside `OFFSET_VERY_FAR1` at $DIR/offset_from_ub.rs:115:14
+
+error[E0080]: evaluation of constant value failed
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::ptr_offset_from(self, origin) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
+ | inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $DIR/offset_from_ub.rs:121:14
+ |
+LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) }
+ | ----------------------------------------- inside `OFFSET_VERY_FAR2` at $DIR/offset_from_ub.rs:121:14
-error: aborting due to 10 previous errors
+error: aborting due to 15 previous errors
For more information about this error, try `rustc --explain E0080`.
#![deny(unaligned_references)]
-// check that derive on a packed struct with non-Copy fields
-// correctly. This can't be made to work perfectly because
-// we can't just use the field from the struct as it might
-// not be aligned.
+// Check that deriving certain builtin traits on certain packed structs cause
+// errors. This happens when the derived trait would need to use a potentially
+// misaligned reference. But there are two cases that are allowed:
+// - If all the fields within the struct meet the required alignment: 1 for
+// `repr(packed)`, or `N` for `repr(packed(N))`.
+// - If `Default` is the only trait derived, because it doesn't involve any
+// references.
-#[derive(Copy, Clone, PartialEq, Eq)]
-//~^ ERROR `#[derive]` can't be used
+#[derive(Copy, Clone, Default, PartialEq, Eq)]
+//~^ ERROR `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters
//~| hard error
-//~^^^ ERROR `#[derive]` can't be used
+//~^^^ ERROR `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters
//~| hard error
#[repr(packed)]
pub struct Foo<T>(T, T, T);
-#[derive(PartialEq, Eq)]
-//~^ ERROR `#[derive]` can't be used
+#[derive(Default, Hash)]
+//~^ ERROR `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
//~| hard error
#[repr(packed)]
pub struct Bar(u32, u32, u32);
-#[derive(PartialEq)]
+// This one is fine because the field alignment is 1.
+#[derive(Default, Hash)]
+#[repr(packed)]
+pub struct Bar2(u8, i8, bool);
+
+// This one is fine because the field alignment is 2, matching `packed(2)`.
+#[derive(Default, Hash)]
+#[repr(packed(2))]
+pub struct Bar3(u16, i16, bool);
+
+// This one is fine because it's not packed.
+#[derive(Debug, Default)]
struct Y(usize);
-#[derive(PartialEq)]
-//~^ ERROR `#[derive]` can't be used
+#[derive(Debug, Default)]
+//~^ ERROR `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
//~| hard error
#[repr(packed)]
struct X(Y);
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133)
- --> $DIR/deriving-with-repr-packed.rs:8:16
+error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters
+ --> $DIR/deriving-with-repr-packed.rs:11:16
|
-LL | #[derive(Copy, Clone, PartialEq, Eq)]
+LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
| ^^^^^
|
note: the lint level is defined here
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133)
- --> $DIR/deriving-with-repr-packed.rs:8:23
+error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters
+ --> $DIR/deriving-with-repr-packed.rs:11:32
|
-LL | #[derive(Copy, Clone, PartialEq, Eq)]
- | ^^^^^^^^^
+LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
+ | ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
- --> $DIR/deriving-with-repr-packed.rs:16:10
+error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
+ --> $DIR/deriving-with-repr-packed.rs:19:19
|
-LL | #[derive(PartialEq, Eq)]
- | ^^^^^^^^^
+LL | #[derive(Default, Hash)]
+ | ^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
- = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
- --> $DIR/deriving-with-repr-packed.rs:25:10
+error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
+ --> $DIR/deriving-with-repr-packed.rs:39:10
|
-LL | #[derive(PartialEq)]
- | ^^^^^^^^^
+LL | #[derive(Debug, Default)]
+ | ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
- = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 4 previous errors
Future incompatibility report: Future breakage diagnostic:
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133)
- --> $DIR/deriving-with-repr-packed.rs:8:16
+error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters
+ --> $DIR/deriving-with-repr-packed.rs:11:16
|
-LL | #[derive(Copy, Clone, PartialEq, Eq)]
+LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
| ^^^^^
|
note: the lint level is defined here
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133)
- --> $DIR/deriving-with-repr-packed.rs:8:23
+error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters
+ --> $DIR/deriving-with-repr-packed.rs:11:32
|
-LL | #[derive(Copy, Clone, PartialEq, Eq)]
- | ^^^^^^^^^
+LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
+ | ^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/deriving-with-repr-packed.rs:1:9
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
- --> $DIR/deriving-with-repr-packed.rs:16:10
+error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
+ --> $DIR/deriving-with-repr-packed.rs:19:19
|
-LL | #[derive(PartialEq, Eq)]
- | ^^^^^^^^^
+LL | #[derive(Default, Hash)]
+ | ^^^^
|
note: the lint level is defined here
--> $DIR/deriving-with-repr-packed.rs:1:9
| ^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
- = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
- --> $DIR/deriving-with-repr-packed.rs:25:10
+error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
+ --> $DIR/deriving-with-repr-packed.rs:39:10
|
-LL | #[derive(PartialEq)]
- | ^^^^^^^^^
+LL | #[derive(Debug, Default)]
+ | ^^^^^
|
note: the lint level is defined here
--> $DIR/deriving-with-repr-packed.rs:1:9
| ^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
- = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
LL ~ B(&'a bool),
|
+error[E0106]: missing lifetime specifier
+ --> $DIR/E0106.rs:10:14
+ |
+LL | type MyStr = &str;
+ | ^ expected named lifetime parameter
+ |
+help: consider introducing a named lifetime parameter
+ |
+LL | type MyStr<'a> = &'a str;
+ | ++++ ++
+
error[E0106]: missing lifetime specifier
--> $DIR/E0106.rs:17:10
|
LL ~ buzz: Buzz<'a, 'a>,
|
-error[E0106]: missing lifetime specifier
- --> $DIR/E0106.rs:10:14
- |
-LL | type MyStr = &str;
- | ^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type MyStr<'a> = &'a str;
- | ++++ ++
-
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0106`.
+++ /dev/null
-static FOO: i32 = 42;
-static BAR: i32 = 42;
-
-static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
-//~^ ERROR pointers cannot be reliably compared during const eval
-
-fn main() {
-}
+++ /dev/null
-error: pointers cannot be reliably compared during const eval
- --> $DIR/E0395.rs:4:29
- |
-LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-
-error: aborting due to previous error
-
LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
| ^^ `'_` is a reserved lifetime name
-error[E0637]: `&` without an explicit lifetime name cannot be used here
- --> $DIR/E0637.rs:13:13
- |
-LL | T: Into<&u32>,
- | ^ explicit lifetime name needed here
-
error[E0106]: missing lifetime specifier
--> $DIR/E0637.rs:1:62
|
LL | fn underscore_lifetime<'a, '_>(str1: &'a str, str2: &'a str) -> &'a str {
| +++ ~~ ~~ ~~
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+ --> $DIR/E0637.rs:13:13
+ |
+LL | T: Into<&u32>,
+ | ^ explicit lifetime name needed here
+
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0106, E0637.
help: consider using the `'static` lifetime
|
LL | pub fn f() -> &'static u8;
- | ~~~~~~~~
+ | +++++++
error: aborting due to previous error
}
impl <T, T1> Foo for T {
+ //~^ ERROR: the type parameter `T1` is not constrained
type F<T1> = &[u8];
//~^ ERROR: the name `T1` is already used for
- //~| ERROR: missing lifetime specifier
+ //~| ERROR: `&` without an explicit lifetime name cannot be used here
}
fn main() {}
error[E0403]: the name `T1` is already used for a generic parameter in this item's generic parameters
- --> $DIR/gat-trait-path-generic-type-arg.rs:10:12
+ --> $DIR/gat-trait-path-generic-type-arg.rs:11:12
|
LL | impl <T, T1> Foo for T {
| -- first use of `T1`
+LL |
LL | type F<T1> = &[u8];
| ^^ already used
-error[E0106]: missing lifetime specifier
- --> $DIR/gat-trait-path-generic-type-arg.rs:10:18
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+ --> $DIR/gat-trait-path-generic-type-arg.rs:11:18
|
LL | type F<T1> = &[u8];
- | ^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
+ | ^ explicit lifetime name needed here
+
+error[E0207]: the type parameter `T1` is not constrained by the impl trait, self type, or predicates
+ --> $DIR/gat-trait-path-generic-type-arg.rs:9:10
|
-LL | type F<'a, T1> = &'a [u8];
- | +++ ++
+LL | impl <T, T1> Foo for T {
+ | ^^ unconstrained type parameter
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0106, E0403.
-For more information about an error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0207, E0403, E0637.
+For more information about an error, try `rustc --explain E0207`.
| +++++++++++++++++++
error[E0276]: impl has stricter requirements than trait
- --> $DIR/generic-associated-types-where.rs:22:5
+ --> $DIR/generic-associated-types-where.rs:22:38
|
LL | type Assoc3<T>;
| -------------- definition of `Assoc3` from trait
...
LL | type Assoc3<T> = Vec<T> where T: Iterator;
- | ^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator`
+ | ^^^^^^^^ impl has extra requirement `T: Iterator`
error: aborting due to 2 previous errors
impl<T> Foo for Fooy<T> {
type A<'a> = (&'a ()) where Self: 'static;
- //~^ ERROR `impl` associated type
+ //~^ ERROR impl has stricter requirements than trait
type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
- //~^ ERROR `impl` associated type
+ //~^ ERROR impl has stricter requirements than trait
//~| ERROR lifetime bound not satisfied
type C = String where Self: Copy;
//~^ ERROR the trait bound `T: Copy` is not satisfied
-error: `impl` associated type signature for `A` doesn't match `trait` associated type signature
- --> $DIR/impl_bounds.rs:15:5
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/impl_bounds.rs:15:39
|
LL | type A<'a> where Self: 'a;
- | ---------- expected
+ | ---------- definition of `A` from trait
...
LL | type A<'a> = (&'a ()) where Self: 'static;
- | ^^^^^^^^^^ found
+ | ^^^^^^^ impl has extra requirement `T: 'static`
-error: `impl` associated type signature for `B` doesn't match `trait` associated type signature
- --> $DIR/impl_bounds.rs:17:5
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/impl_bounds.rs:17:48
|
LL | type B<'a, 'b> where 'a: 'b;
- | -------------- expected
+ | -------------- definition of `B` from trait
...
LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
- | ^^^^^^^^^^^^^^ found
+ | ^^ impl has extra requirement `'b: 'a`
error[E0478]: lifetime bound not satisfied
--> $DIR/impl_bounds.rs:17:22
| ^^
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/impl_bounds.rs:20:5
+ --> $DIR/impl_bounds.rs:20:33
|
LL | type C = String where Self: Copy;
- | ^^^^^^ the trait `Copy` is not implemented for `T`
+ | ^^^^ the trait `Copy` is not implemented for `T`
|
note: required because of the requirements on the impl of `Copy` for `Fooy<T>`
--> $DIR/impl_bounds.rs:11:10
|
LL | #[derive(Copy, Clone)]
| ^^^^
-note: the requirement `Fooy<T>: Copy` appears on the associated impl type `C` but not on the corresponding associated trait type
- --> $DIR/impl_bounds.rs:7:5
+note: the requirement `Fooy<T>: Copy` appears on the `impl`'s associated type `C` but not on the corresponding trait's associated type
+ --> $DIR/impl_bounds.rs:7:10
|
LL | trait Foo {
| --- in this trait
...
LL | type C where Self: Clone;
- | ^^^^^^ this trait associated type doesn't have the requirement `Fooy<T>: Copy`
+ | ^ this trait's associated type doesn't have the requirement `Fooy<T>: Copy`
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider restricting type parameter `T`
|
|
LL | #[derive(Copy, Clone)]
| ^^^^
-note: the requirement `Fooy<T>: Copy` appears on the impl method `d` but not on the corresponding trait method
+note: the requirement `Fooy<T>: Copy` appears on the `impl`'s method `d` but not on the corresponding trait's method
--> $DIR/impl_bounds.rs:8:8
|
LL | trait Foo {
| --- in this trait
...
LL | fn d() where Self: Clone;
- | ^ this trait method doesn't have the requirement `Fooy<T>: Copy`
+ | ^ this trait's method doesn't have the requirement `Fooy<T>: Copy`
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider restricting type parameter `T`
|
error: aborting due to 5 previous errors
-Some errors have detailed explanations: E0277, E0478.
-For more information about an error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0276, E0277, E0478.
+For more information about an error, try `rustc --explain E0276`.
error[E0276]: impl has stricter requirements than trait
- --> $DIR/issue-47206-where-clause.rs:12:5
+ --> $DIR/issue-47206-where-clause.rs:12:38
|
LL | type Assoc3<T>;
| -------------- definition of `Assoc3` from trait
...
LL | type Assoc3<T> = Vec<T> where T: Iterator;
- | ^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator`
+ | ^^^^^^^^ impl has extra requirement `T: Iterator`
error: aborting due to previous error
trait Document {
type Cursor<'a>: DocCursor<'a>;
+ //~^ ERROR: missing required bound on `Cursor`
fn cursor(&self) -> Self::Cursor<'_>;
}
error[E0637]: `'_` cannot be used here
- --> $DIR/issue-70304.rs:47:41
+ --> $DIR/issue-70304.rs:48:41
|
LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
| ^^ `'_` is a reserved lifetime name
error[E0106]: missing lifetime specifier
- --> $DIR/issue-70304.rs:47:61
+ --> $DIR/issue-70304.rs:48:61
|
LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
| ^^ expected named lifetime parameter
LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'static>> {
| ~~~~~~~
-error: aborting due to 2 previous errors
+error: missing required bound on `Cursor`
+ --> $DIR/issue-70304.rs:4:5
+ |
+LL | type Cursor<'a>: DocCursor<'a>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+ | |
+ | help: add the required where clause: `where Self: 'a`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0106, E0637.
For more information about an error, try `rustc --explain E0106`.
}
impl Foo for () {
type Assoc<'a, 'b> = () where 'a: 'b;
- //~^ `impl` associated type
+ //~^ impl has stricter requirements than trait
}
fn main() {}
-error: `impl` associated type signature for `Assoc` doesn't match `trait` associated type signature
- --> $DIR/missing-where-clause-on-trait.rs:9:5
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/missing-where-clause-on-trait.rs:9:39
|
LL | type Assoc<'a, 'b>;
- | ------------------ expected
+ | ------------------ definition of `Assoc` from trait
...
LL | type Assoc<'a, 'b> = () where 'a: 'b;
- | ^^^^^^^^^^^^^^^^^^ found
+ | ^^ impl has extra requirement `'a: 'b`
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0276`.
trait X<'a, K: 'a> {
fn foo<'b, L: X<&'b Nested<K>>>();
//~^ ERROR missing lifetime specifier [E0106]
+ //~| ERROR the type `&'b Nested<K>` does not fulfill the required lifetime
}
fn bar<'b, L: X<&'b Nested<i32>>>(){}
| ^ explicit lifetime name needed here
error[E0106]: missing lifetime specifier
- --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:17
- |
-LL | fn bar<'b, L: X<&'b Nested<i32>>>(){}
- | ^ expected named lifetime parameter
- |
-help: consider using the `'b` lifetime
- |
-LL | fn bar<'b, L: X<'b, &'b Nested<i32>>>(){}
- | +++
-
-error[E0106]: missing lifetime specifier
- --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:21
+ --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:20
|
LL | fn foo<'b, L: X<&'b Nested<K>>>();
- | ^ expected named lifetime parameter
+ | ^ expected named lifetime parameter
|
note: these named lifetimes are available to use
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:9
LL | fn foo<'b, L: X<'lifetime, &'b Nested<K>>>();
| ++++++++++
-error: aborting due to 3 previous errors
+error[E0106]: missing lifetime specifier
+ --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:14:16
+ |
+LL | fn bar<'b, L: X<&'b Nested<i32>>>(){}
+ | ^ expected named lifetime parameter
+ |
+help: consider using the `'b` lifetime
+ |
+LL | fn bar<'b, L: X<'b, &'b Nested<i32>>>(){}
+ | +++
+
+error[E0477]: the type `&'b Nested<K>` does not fulfill the required lifetime
+ --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:19
+ |
+LL | fn foo<'b, L: X<&'b Nested<K>>>();
+ | ^^^^^^^^^^^^^^^^
+ |
+note: type must satisfy the static lifetime as required by this binding
+ --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:16
+ |
+LL | trait X<'a, K: 'a> {
+ | ^^
+
+error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0106, E0637.
+Some errors have detailed explanations: E0106, E0477, E0637.
For more information about an error, try `rustc --explain E0106`.
type B = Box<dyn GenericLifetime>;
//~^ ERROR missing lifetime specifier
//~| HELP consider introducing
+ //~| HELP consider making the bound lifetime-generic
type C = Box<dyn GenericLifetime<'static, 'static>>;
//~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
type F = Box<dyn GenericLifetime<>>;
//~^ ERROR missing lifetime specifier
//~| HELP consider introducing
+ //~| HELP consider making the bound lifetime-generic
type G = Box<dyn GenericType<>>;
//~^ ERROR this trait takes 1 generic argument but 0 generic arguments
type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
//~^ ERROR missing lifetime specifier
//~| HELP consider introducing
+ //~| HELP consider making the bound lifetime-generic
type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
//~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
//~^ ERROR missing lifetime specifier
//~| HELP consider introducing
+ //~| HELP consider making the bound lifetime-generic
//~| ERROR this trait takes 0 generic arguments but 1 generic argument
//~| HELP remove
}
//~| HELP add missing
//~| ERROR missing lifetime specifier
//~| HELP consider introducing
+ //~| HELP consider making the bound lifetime-generic
type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
//~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied
type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
//~^ ERROR missing lifetime specifier
//~| HELP consider introducing
+ //~| HELP consider making the bound lifetime-generic
type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
//~^ ERROR missing lifetime specifier
//~| HELP consider introducing
+ //~| HELP consider making the bound lifetime-generic
//~| ERROR this trait takes 1 generic argument but 2 generic arguments
//~| HELP remove
type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
//~^ ERROR missing lifetime specifier
//~| HELP consider introducing
+ //~| HELP consider making the bound lifetime-generic
type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
//~^ ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
//~^ ERROR missing lifetime specifier
//~| HELP consider introducing
+ //~| HELP consider making the bound lifetime-generic
//~| ERROR this trait takes 1 generic argument but 0 generic arguments
//~| HELP add missing
+error[E0106]: missing lifetime specifier
+ --> $DIR/wrong-number-of-args.rs:48:14
+ |
+LL | type A = Ty;
+ | ^^ expected named lifetime parameter
+ |
+help: consider introducing a named lifetime parameter
+ |
+LL | type A<'a> = Ty<'a>;
+ | ++++ ++++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/wrong-number-of-args.rs:58:16
+ |
+LL | type C = Ty<usize>;
+ | ^ expected named lifetime parameter
+ |
+help: consider introducing a named lifetime parameter
+ |
+LL | type C<'a> = Ty<'a, usize>;
+ | ++++ +++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/wrong-number-of-args.rs:64:16
+ |
+LL | type E = Ty<>;
+ | ^ expected named lifetime parameter
+ |
+help: consider introducing a named lifetime parameter
+ |
+LL | type E<'a> = Ty<'a, >;
+ | ++++ +++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/wrong-number-of-args.rs:120:22
+ |
+LL | type B = Box<dyn GenericLifetime>;
+ | ^^^^^^^^^^^^^^^ expected named lifetime parameter
+ |
+ = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | type B = Box<dyn for<'a> GenericLifetime<'a>>;
+ | +++++++ ++++
+help: consider introducing a named lifetime parameter
+ |
+LL | type B<'a> = Box<dyn GenericLifetime<'a>>;
+ | ++++ ++++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/wrong-number-of-args.rs:137:37
+ |
+LL | type F = Box<dyn GenericLifetime<>>;
+ | ^ expected named lifetime parameter
+ |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | type F = Box<dyn for<'a> GenericLifetime<'a, >>;
+ | +++++++ +++
+help: consider introducing a named lifetime parameter
+ |
+LL | type F<'a> = Box<dyn GenericLifetime<'a, >>;
+ | ++++ +++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/wrong-number-of-args.rs:163:43
+ |
+LL | type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
+ | ^ expected named lifetime parameter
+ |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | type A = Box<dyn for<'a> GenericLifetimeAT<'a, AssocTy=()>>;
+ | +++++++ +++
+help: consider introducing a named lifetime parameter
+ |
+LL | type A<'a> = Box<dyn GenericLifetimeAT<'a, AssocTy=()>>;
+ | ++++ +++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/wrong-number-of-args.rs:172:43
+ |
+LL | type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
+ | ^ expected named lifetime parameter
+ |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | type C = Box<dyn for<'a> GenericLifetimeAT<'a, (), AssocTy=()>>;
+ | +++++++ +++
+help: consider introducing a named lifetime parameter
+ |
+LL | type C<'a> = Box<dyn GenericLifetimeAT<'a, (), AssocTy=()>>;
+ | ++++ +++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/wrong-number-of-args.rs:205:47
+ |
+LL | type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
+ | ^ expected named lifetime parameter
+ |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | type A = Box<dyn for<'a> GenericLifetimeTypeAT<'a, AssocTy=()>>;
+ | +++++++ +++
+help: consider introducing a named lifetime parameter
+ |
+LL | type A<'a> = Box<dyn GenericLifetimeTypeAT<'a, AssocTy=()>>;
+ | ++++ +++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/wrong-number-of-args.rs:222:47
+ |
+LL | type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
+ | ^ expected named lifetime parameter
+ |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | type D = Box<dyn for<'a> GenericLifetimeTypeAT<'a, (), AssocTy=()>>;
+ | +++++++ +++
+help: consider introducing a named lifetime parameter
+ |
+LL | type D<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), AssocTy=()>>;
+ | ++++ +++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/wrong-number-of-args.rs:227:47
+ |
+LL | type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
+ | ^ expected named lifetime parameter
+ |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | type E = Box<dyn for<'a> GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>;
+ | +++++++ +++
+help: consider introducing a named lifetime parameter
+ |
+LL | type E<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>;
+ | ++++ +++
+
+error[E0106]: missing lifetime specifiers
+ --> $DIR/wrong-number-of-args.rs:272:51
+ |
+LL | type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
+ | ^ expected 2 lifetime parameters
+ |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | type A = Box<dyn for<'a> GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>;
+ | +++++++ +++++++
+help: consider introducing a named lifetime parameter
+ |
+LL | type A<'a> = Box<dyn GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>;
+ | ++++ +++++++
+
+error[E0106]: missing lifetime specifiers
+ --> $DIR/wrong-number-of-args.rs:287:55
+ |
+LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
+ | ^ expected 2 lifetime parameters
+ |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | type A = Box<dyn for<'a> GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>;
+ | +++++++ +++++++
+help: consider introducing a named lifetime parameter
+ |
+LL | type A<'a> = Box<dyn GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>;
+ | ++++ +++++++
+
error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/wrong-number-of-args.rs:6:14
|
LL | type A = Ty<T>;
| ~~~~~
-error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:48:14
- |
-LL | type A = Ty;
- | ^^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type A<'a> = Ty<'a>;
- | ++++ ~~~~~~
-
error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
--> $DIR/wrong-number-of-args.rs:54:14
|
LL | type B = Ty<'static, T>;
| +++
-error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:58:17
- |
-LL | type C = Ty<usize>;
- | ^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type C<'a> = Ty<'a, usize>;
- | ++++ +++
-
error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
--> $DIR/wrong-number-of-args.rs:64:14
|
LL | type E = Ty<T>;
| +
-error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:64:16
- |
-LL | type E = Ty<>;
- | ^- expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type E<'a> = Ty<'a>;
- | ++++ ++
-
error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
--> $DIR/wrong-number-of-args.rs:70:14
|
LL | trait NonGeneric {
| ^^^^^^^^^^
-error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:120:22
- |
-LL | type B = Box<dyn GenericLifetime>;
- | ^^^^^^^^^^^^^^^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type B<'a> = Box<dyn GenericLifetime<'a>>;
- | ++++ ~~~~~~~~~~~~~~~~~~~
-
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:124:22
+ --> $DIR/wrong-number-of-args.rs:125:22
|
LL | type C = Box<dyn GenericLifetime<'static, 'static>>;
| ^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| ^^^^^^^^^^^^^^^ --
error[E0107]: missing generics for trait `GenericType`
- --> $DIR/wrong-number-of-args.rs:128:22
+ --> $DIR/wrong-number-of-args.rs:129:22
|
LL | type D = Box<dyn GenericType>;
| ^^^^^^^^^^^ expected 1 generic argument
| ~~~~~~~~~~~~~~
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:132:22
+ --> $DIR/wrong-number-of-args.rs:133:22
|
LL | type E = Box<dyn GenericType<String, usize>>;
| ^^^^^^^^^^^ ----- help: remove this generic argument
LL | trait GenericType<A> {
| ^^^^^^^^^^^ -
-error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:136:37
- |
-LL | type F = Box<dyn GenericLifetime<>>;
- | ^- expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type F<'a> = Box<dyn GenericLifetime<'a>>;
- | ++++ ++
-
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:140:22
+ --> $DIR/wrong-number-of-args.rs:142:22
|
LL | type G = Box<dyn GenericType<>>;
| ^^^^^^^^^^^ expected 1 generic argument
| +
error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:151:26
+ --> $DIR/wrong-number-of-args.rs:153:26
|
LL | type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
| ^^^^^^^^^^^^------------------- help: remove these generics
| expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
- --> $DIR/wrong-number-of-args.rs:147:15
+ --> $DIR/wrong-number-of-args.rs:149:15
|
LL | trait NonGenericAT {
| ^^^^^^^^^^^^
-error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:161:44
- |
-LL | type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
- | ^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type A<'a> = Box<dyn GenericLifetimeAT<'a, AssocTy=()>>;
- | ++++ +++
-
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:165:26
+ --> $DIR/wrong-number-of-args.rs:168:26
|
LL | type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:157:15
+ --> $DIR/wrong-number-of-args.rs:159:15
|
LL | trait GenericLifetimeAT<'a> {
| ^^^^^^^^^^^^^^^^^ --
error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:169:26
+ --> $DIR/wrong-number-of-args.rs:172:26
|
LL | type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
- --> $DIR/wrong-number-of-args.rs:157:15
+ --> $DIR/wrong-number-of-args.rs:159:15
|
LL | trait GenericLifetimeAT<'a> {
| ^^^^^^^^^^^^^^^^^
-error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:169:44
- |
-LL | type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
- | ^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type C<'a> = Box<dyn GenericLifetimeAT<'a, (), AssocTy=()>>;
- | ++++ +++
-
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:181:26
+ --> $DIR/wrong-number-of-args.rs:185:26
|
LL | type A = Box<dyn GenericTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:177:15
+ --> $DIR/wrong-number-of-args.rs:181:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^ -
| ++
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:185:26
+ --> $DIR/wrong-number-of-args.rs:189:26
|
LL | type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
| ^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:177:15
+ --> $DIR/wrong-number-of-args.rs:181:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^ -
error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:189:26
+ --> $DIR/wrong-number-of-args.rs:193:26
|
LL | type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^--------------------- help: remove these generics
| expected 0 lifetime arguments
|
note: trait defined here, with 0 lifetime parameters
- --> $DIR/wrong-number-of-args.rs:177:15
+ --> $DIR/wrong-number-of-args.rs:181:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:189:26
+ --> $DIR/wrong-number-of-args.rs:193:26
|
LL | type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:177:15
+ --> $DIR/wrong-number-of-args.rs:181:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^ -
| +++
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:201:26
+ --> $DIR/wrong-number-of-args.rs:205:26
|
LL | type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:197:15
+ --> $DIR/wrong-number-of-args.rs:201:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
LL | type A = Box<dyn GenericLifetimeTypeAT<A, AssocTy=()>>;
| ++
-error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:201:48
- |
-LL | type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
- | ^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type A<'a> = Box<dyn GenericLifetimeTypeAT<'a, AssocTy=()>>;
- | ++++ +++
-
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:207:26
+ --> $DIR/wrong-number-of-args.rs:212:26
|
LL | type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:197:15
+ --> $DIR/wrong-number-of-args.rs:201:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
| +++
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:211:26
+ --> $DIR/wrong-number-of-args.rs:216:26
|
LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:197:15
+ --> $DIR/wrong-number-of-args.rs:201:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ --
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:211:26
+ --> $DIR/wrong-number-of-args.rs:216:26
|
LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:197:15
+ --> $DIR/wrong-number-of-args.rs:201:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, A, AssocTy=()>>;
| +++
-error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:217:48
- |
-LL | type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
- | ^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type D<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), AssocTy=()>>;
- | ++++ +++
-
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:221:26
+ --> $DIR/wrong-number-of-args.rs:227:26
|
LL | type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:197:15
+ --> $DIR/wrong-number-of-args.rs:201:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
-error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:221:48
- |
-LL | type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
- | ^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type E<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>;
- | ++++ +++
-
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:227:26
+ --> $DIR/wrong-number-of-args.rs:234:26
|
LL | type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:197:15
+ --> $DIR/wrong-number-of-args.rs:201:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ --
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:231:26
+ --> $DIR/wrong-number-of-args.rs:238:26
|
LL | type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:197:15
+ --> $DIR/wrong-number-of-args.rs:201:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:235:26
+ --> $DIR/wrong-number-of-args.rs:242:26
|
LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:197:15
+ --> $DIR/wrong-number-of-args.rs:201:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ --
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:235:26
+ --> $DIR/wrong-number-of-args.rs:242:26
|
LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:197:15
+ --> $DIR/wrong-number-of-args.rs:201:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
error[E0107]: this trait takes 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:247:26
+ --> $DIR/wrong-number-of-args.rs:254:26
|
LL | type A = Box<dyn GenericTypeTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ expected 2 generic arguments
|
note: trait defined here, with 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:243:15
+ --> $DIR/wrong-number-of-args.rs:250:15
|
LL | trait GenericTypeTypeAT<A, B> {
| ^^^^^^^^^^^^^^^^^ - -
| +++++
error[E0107]: this trait takes 2 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:251:26
+ --> $DIR/wrong-number-of-args.rs:258:26
|
LL | type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ -- supplied 1 generic argument
| expected 2 generic arguments
|
note: trait defined here, with 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:243:15
+ --> $DIR/wrong-number-of-args.rs:250:15
|
LL | trait GenericTypeTypeAT<A, B> {
| ^^^^^^^^^^^^^^^^^ - -
| +++
error[E0107]: this trait takes 2 generic arguments but 3 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:255:26
+ --> $DIR/wrong-number-of-args.rs:262:26
|
LL | type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 2 generic arguments
|
note: trait defined here, with 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:243:15
+ --> $DIR/wrong-number-of-args.rs:250:15
|
LL | trait GenericTypeTypeAT<A, B> {
| ^^^^^^^^^^^^^^^^^ - -
-error[E0106]: missing lifetime specifiers
- --> $DIR/wrong-number-of-args.rs:265:52
- |
-LL | type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
- | ^ expected 2 lifetime parameters
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type A<'a> = Box<dyn GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>;
- | ++++ +++++++
-
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:269:26
+ --> $DIR/wrong-number-of-args.rs:277:26
|
LL | type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
| expected 2 lifetime arguments
|
note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
- --> $DIR/wrong-number-of-args.rs:261:15
+ --> $DIR/wrong-number-of-args.rs:268:15
|
LL | trait GenericLifetimeLifetimeAT<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
| ++++
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:279:26
+ --> $DIR/wrong-number-of-args.rs:287:26
|
LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:275:15
+ --> $DIR/wrong-number-of-args.rs:283:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -
LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<A, AssocTy=()>>;
| ++
-error[E0106]: missing lifetime specifiers
- --> $DIR/wrong-number-of-args.rs:279:56
- |
-LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
- | ^ expected 2 lifetime parameters
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type A<'a> = Box<dyn GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>;
- | ++++ +++++++
-
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:285:26
+ --> $DIR/wrong-number-of-args.rs:294:26
|
LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
| expected 2 lifetime arguments
|
note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
- --> $DIR/wrong-number-of-args.rs:275:15
+ --> $DIR/wrong-number-of-args.rs:283:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
| ++++
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:285:26
+ --> $DIR/wrong-number-of-args.rs:294:26
|
LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:275:15
+ --> $DIR/wrong-number-of-args.rs:283:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -
| +++
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:291:26
+ --> $DIR/wrong-number-of-args.rs:300:26
|
LL | type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
| expected 2 lifetime arguments
|
note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
- --> $DIR/wrong-number-of-args.rs:275:15
+ --> $DIR/wrong-number-of-args.rs:283:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
| ++++
error[E0107]: missing generics for struct `HashMap`
- --> $DIR/wrong-number-of-args.rs:301:18
+ --> $DIR/wrong-number-of-args.rs:310:18
|
LL | type A = HashMap;
| ^^^^^^^ expected at least 2 generic arguments
| ~~~~~~~~~~~~~
error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:305:18
+ --> $DIR/wrong-number-of-args.rs:314:18
|
LL | type B = HashMap<String>;
| ^^^^^^^ ------ supplied 1 generic argument
| +++
error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:309:18
+ --> $DIR/wrong-number-of-args.rs:318:18
|
LL | type C = HashMap<'static>;
| ^^^^^^^--------- help: remove these generics
| ^^^^^^^
error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:309:18
+ --> $DIR/wrong-number-of-args.rs:318:18
|
LL | type C = HashMap<'static>;
| ^^^^^^^ expected at least 2 generic arguments
| ++++++
error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:315:18
+ --> $DIR/wrong-number-of-args.rs:324:18
|
LL | type D = HashMap<usize, String, char, f64>;
| ^^^^^^^ --- help: remove this generic argument
| ^^^^^^^ - - ---------------
error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:319:18
+ --> $DIR/wrong-number-of-args.rs:328:18
|
LL | type E = HashMap<>;
| ^^^^^^^ expected at least 2 generic arguments
| ++++
error[E0107]: missing generics for enum `Result`
- --> $DIR/wrong-number-of-args.rs:325:18
+ --> $DIR/wrong-number-of-args.rs:334:18
|
LL | type A = Result;
| ^^^^^^ expected 2 generic arguments
| ~~~~~~~~~~~~
error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:329:18
+ --> $DIR/wrong-number-of-args.rs:338:18
|
LL | type B = Result<String>;
| ^^^^^^ ------ supplied 1 generic argument
| +++
error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:333:18
+ --> $DIR/wrong-number-of-args.rs:342:18
|
LL | type C = Result<'static>;
| ^^^^^^--------- help: remove these generics
| ^^^^^^
error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:333:18
+ --> $DIR/wrong-number-of-args.rs:342:18
|
LL | type C = Result<'static>;
| ^^^^^^ expected 2 generic arguments
| ++++++
error[E0107]: this enum takes 2 generic arguments but 3 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:339:18
+ --> $DIR/wrong-number-of-args.rs:348:18
|
LL | type D = Result<usize, String, char>;
| ^^^^^^ ---- help: remove this generic argument
| ^^^^^^ - -
error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:343:18
+ --> $DIR/wrong-number-of-args.rs:352:18
|
LL | type E = Result<>;
| ^^^^^^ expected 2 generic arguments
impl MyTrait for &i32 {
type Output = &i32;
- //~^ ERROR missing lifetime specifier
+ //~^ ERROR `&` without an explicit lifetime name cannot be used here
}
impl MyTrait for &u32 {
type Output = &'_ i32;
- //~^ ERROR missing lifetime specifier
+ //~^ ERROR `'_` cannot be used here
}
// This is what you have to do:
-error[E0106]: missing lifetime specifier
+error[E0637]: `&` without an explicit lifetime name cannot be used here
--> $DIR/assoc-type.rs:11:19
|
LL | type Output = &i32;
- | ^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type Output<'a> = &'a i32;
- | ++++ ++
+ | ^ explicit lifetime name needed here
-error[E0106]: missing lifetime specifier
+error[E0637]: `'_` cannot be used here
--> $DIR/assoc-type.rs:16:20
|
LL | type Output = &'_ i32;
- | ^^ expected named lifetime parameter
- |
-help: consider introducing a named lifetime parameter
- |
-LL | type Output<'a> = &'a i32;
- | ++++ ~~
+ | ^^ `'_` is a reserved lifetime name
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0106`.
+For more information about this error, try `rustc --explain E0637`.
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Swap` captures lifetime that does not appear in bounds
--> $DIR/hidden-lifetimes.rs:29:5
|
LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b {
| ++++
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Swap` captures lifetime that does not appear in bounds
--> $DIR/hidden-lifetimes.rs:46:5
|
LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
fn test<T: Display>(t: T, recurse: bool) -> impl Display {
let f = || {
let i: u32 = test::<i32>(-1, false);
- //~^ ERROR mismatched types
+ //~^ ERROR concrete type differs from previous defining opaque type use
println!("{i}");
};
if recurse {
-error[E0308]: mismatched types
+error: concrete type differs from previous defining opaque type use
--> $DIR/issue-99073-2.rs:9:22
|
-LL | fn test<T: Display>(t: T, recurse: bool) -> impl Display {
- | ------------ the expected opaque type
-LL | let f = || {
LL | let i: u32 = test::<i32>(-1, false);
- | ^^^^^^^^^^^^^^^^^^^^^^ types differ
+ | ^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `u32`
|
- = note: expected opaque type `impl std::fmt::Display`
- found type `u32`
+note: previous use here
+ --> $DIR/issue-99073-2.rs:16:5
+ |
+LL | t
+ | ^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
fn main() {
- let _ = fix(|_: &dyn Fn()| {});
+ let _ = fix(|_: &dyn Fn()| {});
}
fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
- move || f(fix(&f))
- //~^ ERROR mismatched types
+ move || f(fix(&f))
+ //~^ ERROR concrete type differs from previous defining opaque type use
}
-error[E0308]: mismatched types
- --> $DIR/issue-99073.rs:6:13
+error: concrete type differs from previous defining opaque type use
+ --> $DIR/issue-99073.rs:6:11
|
-LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
- | --------- the expected opaque type
-LL | move || f(fix(&f))
- | ^^^^^^^^^^ types differ
+LL | move || f(fix(&f))
+ | ^^^^^^^^^^ expected `[closure@$DIR/issue-99073.rs:6:3: 6:10]`, got `G`
|
- = note: expected opaque type `impl Fn()`
- found type parameter `G`
+note: previous use here
+ --> $DIR/issue-99073.rs:6:3
+ |
+LL | move || f(fix(&f))
+ | ^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
let _: &'b i32 = *u.0;
}
u.0
- //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ //~^ ERROR hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds
}
fn main() {}
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds
--> $DIR/error-handling-2.rs:22:5
|
LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
// 'a in ['d, 'e]
// ```
if condition() { a } else { b }
- //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ //~^ ERROR hidden type for `impl Trait<'d, 'e>` captures lifetime that does not appear in bounds
}
fn condition() -> bool {
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Trait<'d, 'e>` captures lifetime that does not appear in bounds
--> $DIR/ordinary-bounds-unrelated.rs:28:33
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
//
// We are forced to pick that '0 = 'e, because only 'e is outlived by *both* 'a and 'b.
if condition() { a } else { b }
- //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ //~^ ERROR hidden type for `impl Trait<'a, 'b>` captures lifetime that does not appear in bounds
}
fn condition() -> bool {
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Trait<'a, 'b>` captures lifetime that does not appear in bounds
--> $DIR/ordinary-bounds-unsuited.rs:31:33
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear in bounds
--> $DIR/must_outlive_least_region_or_bound.rs:3:35
|
LL | fn elided(x: &i32) -> impl Copy { x }
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
| ++++
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear in bounds
--> $DIR/must_outlive_least_region_or_bound.rs:6:44
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x }
| ~~~~~~~~~~~~
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Fn(&'a u32)` captures lifetime that does not appear in bounds
--> $DIR/must_outlive_least_region_or_bound.rs:38:5
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
LL | impl AnotherTrait for D<OpaqueType> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
|
- = note: downstream crates may implement trait `std::fmt::Debug` for type `OpaqueType`
+ = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
error: cannot implement trait on type alias impl trait
--> $DIR/negative-reasoning.rs:19:25
where 'x: 'y
{
x
- //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0700]
+ //~^ ERROR hidden type for `impl Trait<'y>` captures lifetime that does not appear in bounds [E0700]
}
fn main() { }
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Trait<'y>` captures lifetime that does not appear in bounds
--> $DIR/region-escape-via-bound.rs:17:5
|
LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y>
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
--> $DIR/static-return-lifetime-infered.rs:7:9
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
| ++++
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
--> $DIR/static-return-lifetime-infered.rs:7:9
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
| ++++
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
--> $DIR/static-return-lifetime-infered.rs:12:9
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
| ++++
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
--> $DIR/static-return-lifetime-infered.rs:12:9
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: ~const FnOnce<()>` is not satisfied
+error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: FnOnce<()>` is not satisfied
--> $DIR/const-eval-select-bad.rs:7:27
|
LL | const_eval_select((), || {}, || {});
LL | F: ~const FnOnce<ARG, Output = RET>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
-error[E0277]: the trait bound `{integer}: ~const FnOnce<()>` is not satisfied
+error[E0277]: the trait bound `{integer}: FnOnce<()>` is not satisfied
--> $DIR/const-eval-select-bad.rs:9:27
|
LL | const_eval_select((), 42, 0xDEADBEEF);
LL | #[rustc_legacy_const_generics(1, a, 2, b)]
| ^ ^
-error: attribute should be applied to a function
+error: attribute should be applied to a function definition
--> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:18:1
|
LL | #[rustc_legacy_const_generics(0)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | struct S;
- | --------- not a function
+ | --------- not a function definition
error: #[rustc_legacy_const_generics] functions must only have const generics
--> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:1
LL | fn foo8<X>() {}
| - non-const generic parameter
-error: attribute should be applied to a function
+error: attribute should be applied to a function definition
--> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:33:5
|
LL | #[rustc_legacy_const_generics(0)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | fn foo9<const X: usize>() {}
- | ---------------------------- not a function
+ | ---------------------------- not a function definition
-error: attribute should be applied to a function
+error: attribute should be applied to a function definition
--> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:5
|
LL | #[rustc_legacy_const_generics(1)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | fn foo7<const X: usize>();
- | -------------------------- not a function
+ | -------------------------- not a function definition
error[E0044]: foreign items may not have const parameters
--> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:26:5
help: consider using the `'static` lifetime
|
LL | &'static str
- | ~~~~~~~~
+ | +++++++
error: aborting due to previous error
| --- --- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
- = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the bound lifetime-generic with a new `'a` lifetime
|
LL | fn bar<F: for<'a> Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {}
= help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from
help: consider introducing a named lifetime parameter
|
-LL | fn f<'a>(a: &'a S, b: i32) -> &'a i32 {
- | ++++ ++ ++
+LL | fn f<'a>(a: &'a S<'a>, b: i32) -> &'a i32 {
+ | ++++ ++ ++++ ++
error[E0106]: missing lifetime specifier
--> $DIR/issue-30255.rs:14:34
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c`
help: consider introducing a named lifetime parameter
|
-LL | fn g<'a>(a: &'a S, b: bool, c: &'a i32) -> &'a i32 {
- | ++++ ++ ++ ++
+LL | fn g<'a>(a: &'a S<'a>, b: bool, c: &'a i32) -> &'a i32 {
+ | ++++ ++ ++++ ++ ++
error[E0106]: missing lifetime specifier
--> $DIR/issue-30255.rs:19:44
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d`
help: consider introducing a named lifetime parameter
|
-LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S, d: &'a i32) -> &'a i32 {
- | ++++ ++ ++ ++ ++
+LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S<'a>, d: &'a i32) -> &'a i32 {
+ | ++++ ++ ++ ++++ ++ ++
error: aborting due to 3 previous errors
// run-pass
#![allow(unreachable_code)]
-#![allow(unused_mut)] // rust-lang/rust#54586
#![deny(unused_variables)]
fn main() {
fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
//~^ ERROR missing lifetime specifier [E0106]
+//~| ERROR mismatched types
fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
//~^ ERROR missing lifetime specifier [E0106]
+//~| ERROR mismatched types
+//~| ERROR this function takes 1 argument but 0 arguments were supplied
fn parse_type_3() -> &str { unimplemented!() }
//~^ ERROR missing lifetime specifier [E0106]
= help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from
help: consider introducing a named lifetime parameter
|
-LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'a str { iter.next() }
- | ++++ ++
+LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&'a str>+'static>) -> &'a str { iter.next() }
+ | ++++ ++ ++
error[E0106]: missing lifetime specifier
- --> $DIR/issue-26638.rs:4:40
+ --> $DIR/issue-26638.rs:5:40
|
LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
| ^ expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() }
- | ~~~~~~~~
+ | +++++++
error[E0106]: missing lifetime specifier
- --> $DIR/issue-26638.rs:7:22
+ --> $DIR/issue-26638.rs:10:22
|
LL | fn parse_type_3() -> &str { unimplemented!() }
| ^ expected named lifetime parameter
help: consider using the `'static` lifetime
|
LL | fn parse_type_3() -> &'static str { unimplemented!() }
- | ~~~~~~~~
+ | +++++++
+
+error[E0308]: mismatched types
+ --> $DIR/issue-26638.rs:1:69
+ |
+LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
+ | ---- ^^^^^^^^^^^ expected `&str`, found enum `Option`
+ | |
+ | expected `&'static str` because of return type
+ |
+ = note: expected reference `&'static str`
+ found enum `Option<&str>`
+
+error[E0061]: this function takes 1 argument but 0 arguments were supplied
+ --> $DIR/issue-26638.rs:5:47
+ |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
+ | ^^^^-- an argument of type `&u8` is missing
+ |
+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
+ |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
+ | ---- ^^^^^^ expected `str`, found `u8`
+ | |
+ | expected `&'static str` because of return type
+ |
+ = note: expected reference `&'static str`
+ found reference `&u8`
-error: aborting due to 3 previous errors
+error: aborting due to 6 previous errors
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0061, E0106, E0308.
+For more information about an error, try `rustc --explain E0061`.
help: consider using the `'static` lifetime
|
LL | fn f() -> &'static isize {
- | ~~~~~~~~
+ | +++++++
error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33
= help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from
help: consider introducing a named lifetime parameter
|
-LL | fn h<'a>(_x: &'a Foo) -> &'a isize {
- | ++++ ++ ++
+LL | fn h<'a>(_x: &'a Foo<'a>) -> &'a isize {
+ | ++++ ++ ++++ ++
error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20
LL | fn i(_x: isize) -> &isize {
| ^ expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
LL | fn i(_x: isize) -> &'static isize {
- | ~~~~~~~~
+ | +++++++
error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:34:24
LL | fn j(_x: StaticStr) -> &isize {
| ^ expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
LL | fn j(_x: StaticStr) -> &'static isize {
- | ~~~~~~~~
+ | +++++++
error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:40:49
LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize {
| ^ expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'a` lifetime
|
LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &'a isize {
- | ~~~
+ | ++
error: aborting due to 6 previous errors
if x > y { x } else { y }
}
-fn main() { }
+fn main() {}
help: consider using the `'a` lifetime
|
LL | type B<'a> = <A<'a> as Trait<'a>>::Foo;
- | ~~~~~~~~~
+ | ++++
error[E0106]: missing lifetime specifier
--> $DIR/missing-lifetime-in-alias.rs:26:28
|
LL | type C<'a, 'b> = <A<'a> as Trait>::Bar;
| ^^ ^^
+help: consider using one of the available lifetimes here
+ |
+LL | type C<'a, 'b> = <A<'a> as Trait<'lifetime>>::Bar;
+ | +++++++++++
error[E0107]: missing generics for associated type `Trait::Bar`
--> $DIR/missing-lifetime-in-alias.rs:26:36
type Item = IteratorChunk<T, S>; //~ ERROR missing lifetime
fn next(&mut self) -> Option<IteratorChunk<T, S>> {
+ //~^ ERROR `impl` item signature doesn't match `trait` item signature
todo!()
}
}
error[E0106]: missing lifetime specifier
- --> $DIR/issue-74918-missing-lifetime.rs:9:31
+ --> $DIR/issue-74918-missing-lifetime.rs:9:30
|
LL | type Item = IteratorChunk<T, S>;
- | ^ expected named lifetime parameter
+ | ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
LL | type Item<'a> = IteratorChunk<'a, T, S>;
| ++++ +++
-error: aborting due to previous error
+error: `impl` item signature doesn't match `trait` item signature
+ --> $DIR/issue-74918-missing-lifetime.rs:11:5
+ |
+LL | fn next(&mut self) -> Option<IteratorChunk<T, S>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
+ |
+ ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+ |
+LL | fn next(&mut self) -> Option<Self::Item>;
+ | ----------------------------------------- expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
+ |
+ = note: expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
+ found `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
+ = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+ = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0106`.
--- /dev/null
+// run-rustfix
+
+macro_rules! my_wrapper {
+ ($expr:expr) => { MyWrapper($expr) }
+}
+
+pub struct MyWrapper(u32);
+
+fn main() {
+ let value = MyWrapper(123);
+ some_fn(value); //~ ERROR mismatched types
+ some_fn(my_wrapper!(123)); //~ ERROR mismatched types
+}
+
+fn some_fn(wrapped: MyWrapper) {
+ drop(wrapped);
+}
--- /dev/null
+// run-rustfix
+
+macro_rules! my_wrapper {
+ ($expr:expr) => { MyWrapper($expr) }
+}
+
+pub struct MyWrapper(u32);
+
+fn main() {
+ let value = MyWrapper(123);
+ some_fn(value.0); //~ ERROR mismatched types
+ some_fn(my_wrapper!(123).0); //~ ERROR mismatched types
+}
+
+fn some_fn(wrapped: MyWrapper) {
+ drop(wrapped);
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/suggest-removing-tulpe-struct-field.rs:11:13
+ |
+LL | some_fn(value.0);
+ | ------- ^^^^^^^ expected struct `MyWrapper`, found `u32`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/suggest-removing-tulpe-struct-field.rs:15:4
+ |
+LL | fn some_fn(wrapped: MyWrapper) {
+ | ^^^^^^^ ------------------
+help: consider removing the tuple struct field `0`
+ |
+LL - some_fn(value.0);
+LL + some_fn(value);
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-removing-tulpe-struct-field.rs:12:13
+ |
+LL | some_fn(my_wrapper!(123).0);
+ | ------- ^^^^^^^^^^^^^^^^^^ expected struct `MyWrapper`, found `u32`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/suggest-removing-tulpe-struct-field.rs:15:4
+ |
+LL | fn some_fn(wrapped: MyWrapper) {
+ | ^^^^^^^ ------------------
+help: consider removing the tuple struct field `0`
+ |
+LL - some_fn(my_wrapper!(123).0);
+LL + some_fn(my_wrapper!(123));
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Iterator<Item = u8>` captures lifetime that does not appear in bounds
--> $DIR/issue-73159-rpit-static.rs:8:9
|
LL | impl<'a> Foo<'a> {
impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct {
const AC: Option<&'c str> = None;
- //~^ ERROR: mismatched types
+ //~^ ERROR: const not compatible with trait
}
struct OKStruct2 { }
-error[E0308]: mismatched types
+error[E0308]: const not compatible with trait
--> $DIR/trait-associated-constant.rs:21:5
|
LL | const AC: Option<&'c str> = None;
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `Opaque(DefId(0:11 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReStatic, T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds
--> $DIR/impl-trait-captures.rs:11:5
|
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
// dont-check-compiler-stderr
// only-linux
// no-prefer-dynamic
-// compile-flags: -Ctarget-feature=+crt-static -Crpath=no
+// compile-flags: -Ctarget-feature=+crt-static -Crpath=no -Crelocation-model=static
#![feature(exit_status_error)]
#![feature(rustc_private)]
extern crate libc;
trait Foo {
fn fn_with_type_named_same_as_local_in_param(b: b);
- //~^ ERROR cannot find type `b` in this scope
+ //~^ ERROR cannot find type `b` in this scope [E0412]
}
pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
*t == *t
//~^ ERROR can't compare
- //~| ERROR cannot call non-const
}
fn main() {}
-error[E0277]: can't compare `T` with `T` in const contexts
- --> $DIR/call-generic-method-fail.rs:4:5
+error[E0277]: can't compare `T` with `_` in const contexts
+ --> $DIR/call-generic-method-fail.rs:4:8
|
LL | *t == *t
- | ^^^^^^^^ no implementation for `T == T`
+ | ^^ no implementation for `T == _`
|
-note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const`
- --> $DIR/call-generic-method-fail.rs:4:5
+note: the trait `PartialEq<_>` is implemented for `T`, but that implementation is not `const`
+ --> $DIR/call-generic-method-fail.rs:4:8
|
LL | *t == *t
- | ^^^^^^^^
+ | ^^
+ = help: the trait `PartialEq<&B>` is implemented for `&A`
-error[E0015]: cannot call non-const operator in constant functions
- --> $DIR/call-generic-method-fail.rs:4:5
- |
-LL | *t == *t
- | ^^^^^^^^
- |
- = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
- |
-LL | pub const fn equals_self<T: PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
- | ++++++++++++++++++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0015, E0277.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0277`.
const fn test() {
NonConstImpl.a();
//~^ ERROR the trait bound
- //~| ERROR cannot call non-const fn
ConstImpl.a();
}
--> $DIR/const-default-method-bodies.rs:24:18
|
LL | NonConstImpl.a();
- | ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
+ | ^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
|
note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const`
--> $DIR/const-default-method-bodies.rs:24:18
|
LL | NonConstImpl.a();
- | ^^^
-
-error[E0015]: cannot call non-const fn `<NonConstImpl as ConstDefaultFn>::a` in constant functions
- --> $DIR/const-default-method-bodies.rs:24:18
- |
-LL | NonConstImpl.a();
- | ^^^
+ | ^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
- = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+LL | const fn test() where NonConstImpl: ~const ConstDefaultFn {
+ | +++++++++++++++++++++++++++++++++++++++++
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0015, E0277.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
- --> $DIR/cross-crate.rs:15:14
- |
-LL | NonConst.func();
- | ^^^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
- |
-note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const`
- --> $DIR/cross-crate.rs:15:14
- |
-LL | NonConst.func();
- | ^^^^^^
-
-error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
- --> $DIR/cross-crate.rs:15:14
- |
-LL | NonConst.func();
- | ^^^^^^
- |
- = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0015, E0277.
-For more information about an error, try `rustc --explain E0015`.
--- /dev/null
+error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
+ --> $DIR/cross-crate.rs:17:14
+ |
+LL | NonConst.func();
+ | ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
+ |
+note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const`
+ --> $DIR/cross-crate.rs:17:14
+ |
+LL | NonConst.func();
+ | ^^^^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+ |
+LL | const fn const_context() where cross_crate::NonConst: ~const cross_crate::MyTrait {
+ | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
-// revisions: stock gated
-#![cfg_attr(gated, feature(const_trait_impl))]
+// revisions: stock gated stocknc gatednc
+// [gated] check-pass
+#![cfg_attr(any(gated, gatednc), feature(const_trait_impl))]
// aux-build: cross-crate.rs
extern crate cross_crate;
}
const fn const_context() {
- NonConst.func(); //~ ERROR: cannot call non-const fn
- //[gated]~^ ERROR: the trait bound
+ #[cfg(any(stocknc, gatednc))]
+ NonConst.func();
+ //[stocknc]~^ ERROR: the trait bound
+ //[gatednc]~^^ ERROR: the trait bound
Const.func();
- //[stock]~^ ERROR: cannot call non-const fn
+ //[stock]~^ ERROR: cannot call
}
fn main() {}
-error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
- --> $DIR/cross-crate.rs:15:14
- |
-LL | NonConst.func();
- | ^^^^^^
- |
- = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
- --> $DIR/cross-crate.rs:17:11
+ --> $DIR/cross-crate.rs:20:11
|
LL | Const.func();
| ^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0015`.
--- /dev/null
+error[E0277]: the trait bound `cross_crate::NonConst: cross_crate::MyTrait` is not satisfied
+ --> $DIR/cross-crate.rs:17:14
+ |
+LL | NonConst.func();
+ | ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
+ |
+note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const`
+ --> $DIR/cross-crate.rs:17:14
+ |
+LL | NonConst.func();
+ | ^^^^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+ |
+LL | const fn const_context() where cross_crate::NonConst: ~const cross_crate::MyTrait {
+ | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
fn b(&self) {
().a()
//~^ ERROR the trait bound
- //~| ERROR cannot call
}
}
--> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
|
LL | ().a()
- | ^^^ the trait `~const Tr` is not implemented for `()`
+ | ^ the trait `~const Tr` is not implemented for `()`
|
note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
--> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
|
LL | ().a()
- | ^^^
-
-error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions
- --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
- |
-LL | ().a()
- | ^^^
+ | ^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
- = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+LL | pub trait Tr where (): ~const Tr {
+ | +++++++++++++++++++
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0015, E0277.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0277`.
//~^ ERROR missing lifetime specifier [E0106]
&(non_elidable as fn(&u8, &u8) -> &u8);
//~^ ERROR missing lifetime specifier [E0106]
+ //~| ERROR non-primitive cast
fn main() {}
| --- --- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
- = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the type lifetime-generic with a new `'a` lifetime
|
LL | &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
| +++++++ ++ ++ ++
-error: aborting due to 2 previous errors
+error[E0605]: non-primitive cast: `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {non_elidable}` as `for<'r, 's> fn(&'r u8, &'s u8) -> &u8`
+ --> $DIR/rfc1623-2.rs:10:6
+ |
+LL | &(non_elidable as fn(&u8, &u8) -> &u8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
+
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0106, E0605.
+For more information about an error, try `rustc --explain E0106`.
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Clone` captures lifetime that does not appear in bounds
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Clone` captures lifetime that does not appear in bounds
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
|
LL | fn f(self: Pin<&Self>) -> impl Clone { self }
--- /dev/null
+#![crate_type = "lib"]
+
+extern crate core;
+
+pub mod __private {
+ #[doc(hidden)]
+ pub use core::option::Option::{self, None, Some};
+}
--- /dev/null
+#![crate_type = "lib"]
+
+extern crate core;
+
+#[doc(hidden)]
+pub mod __private {
+ pub use core::option::Option::{self, None, Some};
+}
--- /dev/null
+// aux-build:hidden-child.rs
+
+// FIXME(compiler-errors): This currently suggests the wrong thing.
+// UI test exists to track the problem.
+
+extern crate hidden_child;
+
+fn main() {
+ let x: Option<i32> = 1i32; //~ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/hidden-child.rs:9:26
+ |
+LL | let x: Option<i32> = 1i32;
+ | ----------- ^^^^ expected enum `Option`, found `i32`
+ | |
+ | expected due to this
+ |
+ = note: expected enum `Option<i32>`
+ found type `i32`
+help: try wrapping the expression in `hidden_child::__private::Some`
+ |
+LL | let x: Option<i32> = hidden_child::__private::Some(1i32);
+ | ++++++++++++++++++++++++++++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// aux-build:hidden-parent.rs
+
+extern crate hidden_parent;
+
+fn main() {
+ let x: Option<i32> = 1i32; //~ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/hidden-parent.rs:6:26
+ |
+LL | let x: Option<i32> = 1i32;
+ | ----------- ^^^^ expected enum `Option`, found `i32`
+ | |
+ | expected due to this
+ |
+ = note: expected enum `Option<i32>`
+ found type `i32`
+help: try wrapping the expression in `Some`
+ |
+LL | let x: Option<i32> = Some(1i32);
+ | +++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
| ---- ---- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
- = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the bound lifetime-generic with a new `'a` lifetime
|
LL | struct S2<F: for<'a> Fn(&'a i32, &'a i32) -> &'a i32>(F);
-error[E0658]: anonymous lifetimes in `impl Trait` are unstable
- --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31
- |
-LL | fn f(_: impl Iterator<Item = &'_ ()>) {}
- | ^^
- |
- = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
-
error[E0106]: missing lifetime specifier
--> $DIR/impl-trait-missing-lifetime-gated.rs:8:50
|
LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
| ^^ expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
| ~~~~~~~
-error[E0658]: anonymous lifetimes in `impl Trait` are unstable
- --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31
- |
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
- | ^^
- |
- = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
-
error[E0106]: missing lifetime specifier
--> $DIR/impl-trait-missing-lifetime-gated.rs:18:56
|
LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
| ^^ expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
| ~~~~~~~
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+ --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31
+ |
+LL | fn f(_: impl Iterator<Item = &'_ ()>) {}
+ | ^^
+ |
+ = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+ --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31
+ |
+LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+ | ^^
+ |
+ = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0106, E0658.
fn f(_: impl Iterator<Item = &'_ ()>) {}
// But that lifetime does not participate in resolution.
-fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
//~^ ERROR missing lifetime specifier
// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
async fn h(_: impl Iterator<Item = &'_ ()>) {}
// But that lifetime does not participate in resolution.
-async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
//~^ ERROR missing lifetime specifier
+//~| ERROR lifetime may not live long enough
fn main() {}
error[E0106]: missing lifetime specifier
- --> $DIR/impl-trait-missing-lifetime.rs:9:50
+ --> $DIR/impl-trait-missing-lifetime.rs:9:54
|
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
- | ^^ expected named lifetime parameter
+LL | fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+ | ^^ expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
- | ~~~~~~~
+LL | fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+ | ~~~~~~~
error[E0106]: missing lifetime specifier
- --> $DIR/impl-trait-missing-lifetime.rs:16:56
+ --> $DIR/impl-trait-missing-lifetime.rs:16:60
|
-LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
- | ^^ expected named lifetime parameter
+LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+ | ^^ expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
-LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
- | ~~~~~~~
+LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+ | ~~~~~~~
-error: aborting due to 2 previous errors
+error: lifetime may not live long enough
+ --> $DIR/impl-trait-missing-lifetime.rs:16:69
+ |
+LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+ | -------------- ^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+ | |
+ | return type `impl Future<Output = Option<&'static ()>>` contains a lifetime `'1`
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0106`.
async fn a(s1: &str, s2: &str) -> &str {
//~^ ERROR: missing lifetime specifier [E0106]
s1
+//~^ ERROR: lifetime may not live long enough
}
fn b(s1: &str, s2: &str) -> &str {
| ++++ ++ ++ ++
error[E0106]: missing lifetime specifier
- --> $DIR/issue-86667.rs:11:29
+ --> $DIR/issue-86667.rs:12:29
|
LL | fn b(s1: &str, s2: &str) -> &str {
| ---- ---- ^ expected named lifetime parameter
LL | fn b<'a>(s1: &'a str, s2: &'a str) -> &'a str {
| ++++ ++ ++ ++
-error: aborting due to 2 previous errors
+error: lifetime may not live long enough
+ --> $DIR/issue-86667.rs:8:5
+ |
+LL | async fn a(s1: &str, s2: &str) -> &str {
+ | - let's call the lifetime of this reference `'1`
+LL |
+LL | s1
+ | ^^ returning this value requires that `'1` must outlive `'static`
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0106`.
G: Get<T>,
{
move || {
- //~^ ERROR hidden type for `impl Trait` captures lifetime
+ //~^ ERROR hidden type for `impl FnOnce()` captures lifetime
*dest = g.get();
}
}
| |
| help: consider introducing lifetime `'a` here: `'a,`
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl FnOnce()` captures lifetime that does not appear in bounds
--> $DIR/missing-lifetimes-in-signature.rs:19:5
|
LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
LL | const A: &str = "";
| ^ expected named lifetime parameter
|
-help: consider using the `'static` lifetime
- |
-LL | const A: &'static str = "";
- | +++++++
help: consider introducing a named lifetime parameter
|
LL ~ trait ZstAssert<'a>: Sized {
LL | const B: S = S { s: &() };
| ^ expected named lifetime parameter
|
-help: consider using the `'static` lifetime
- |
-LL | const B: S<'static> = S { s: &() };
- | +++++++++
help: consider introducing a named lifetime parameter
|
LL ~ trait ZstAssert<'a>: Sized {
LL | const C: &'_ str = "";
| ^^ expected named lifetime parameter
|
-help: consider using the `'static` lifetime
- |
-LL | const C: &'static str = "";
- | ~~~~~~~
help: consider introducing a named lifetime parameter
|
LL ~ trait ZstAssert<'a>: Sized {
LL | const D: T = T { a: &(), b: &() };
| ^ expected 2 lifetime parameters
|
-help: consider using the `'static` lifetime
- |
-LL | const D: T<'static, 'static> = T { a: &(), b: &() };
- | ++++++++++++++++++
help: consider introducing a named lifetime parameter
|
LL ~ trait ZstAssert<'a>: Sized {
}
thread_local! {
static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
- //~^ ERROR missing lifetime specifier
- //~| ERROR missing lifetime specifier
- //~| ERROR missing lifetime specifier
- //~| ERROR missing lifetime specifier
+ //~^ ERROR missing lifetime specifiers
+ //~| ERROR missing lifetime specifiers
}
thread_local! {
static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
- //~^ ERROR missing lifetime
- //~| ERROR missing lifetime
+ //~^ ERROR missing lifetime specifiers
+ //~| ERROR missing lifetime specifiers
}
thread_local! {
static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
- //~^ ERROR missing lifetime
- //~| ERROR missing lifetime
- //~| ERROR missing lifetime
- //~| ERROR missing lifetime
+ //~^ ERROR missing lifetime specifiers
+ //~| ERROR missing lifetime specifiers
}
thread_local! {
help: consider using the `'static` lifetime
|
LL | static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefCell::new(HashMap::new());
- | ~~~~~~~~~~~~~~~~~~~~~
+ | ++++++++++++++++++
error[E0106]: missing lifetime specifiers
--> $DIR/missing-lifetime-specifier.rs:18:44
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
-error[E0106]: missing lifetime specifier
+error[E0106]: missing lifetime specifiers
--> $DIR/missing-lifetime-specifier.rs:23:44
|
LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
- | ^ expected named lifetime parameter
+ | ^^^^ expected 2 lifetime parameters
+ | |
+ | expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
-LL | static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar>>>> = RefCell::new(HashMap::new());
- | ~~~~~~~~
+LL | static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar<'static, 'static>>>>> = RefCell::new(HashMap::new());
+ | +++++++ ++++++++++++++++++
error[E0106]: missing lifetime specifiers
- --> $DIR/missing-lifetime-specifier.rs:23:45
- |
-LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
- | ^^^ expected 2 lifetime parameters
- |
- = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
- |
-LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar<'static, 'static>>>>> = RefCell::new(HashMap::new());
- | ~~~~~~~~~~~~~~~~~~~~~
-
-error[E0106]: missing lifetime specifier
--> $DIR/missing-lifetime-specifier.rs:23:44
|
LL | / thread_local! {
LL | | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
- | | ^ expected named lifetime parameter
-LL | |
-LL | |
+ | | ^^^^ expected 2 lifetime parameters
+ | | |
+ | | expected named lifetime parameter
LL | |
LL | |
LL | | }
= help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
error[E0106]: missing lifetime specifiers
- --> $DIR/missing-lifetime-specifier.rs:23:45
- |
-LL | / thread_local! {
-LL | | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
- | | ^^^ expected 2 lifetime parameters
-LL | |
-LL | |
-LL | |
-LL | |
-LL | | }
- | |_-
- |
- = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
-
-error[E0106]: missing lifetime specifiers
- --> $DIR/missing-lifetime-specifier.rs:30:48
+ --> $DIR/missing-lifetime-specifier.rs:28:47
|
LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
- | ^ expected 2 lifetime parameters
+ | ^ expected 2 lifetime parameters
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
| +++++++++++++++++
error[E0106]: missing lifetime specifiers
- --> $DIR/missing-lifetime-specifier.rs:30:48
+ --> $DIR/missing-lifetime-specifier.rs:28:47
|
LL | / thread_local! {
LL | | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
- | | ^ expected 2 lifetime parameters
+ | | ^ expected 2 lifetime parameters
LL | |
LL | |
LL | | }
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
-error[E0106]: missing lifetime specifier
- --> $DIR/missing-lifetime-specifier.rs:35:44
- |
-LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
- | ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
- |
-LL | static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<i32>>>>> = RefCell::new(HashMap::new());
- | ~~~~~~~~
-
error[E0106]: missing lifetime specifiers
- --> $DIR/missing-lifetime-specifier.rs:35:49
+ --> $DIR/missing-lifetime-specifier.rs:33:44
|
LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
- | ^ expected 2 lifetime parameters
+ | ^ ^ expected 2 lifetime parameters
+ | |
+ | expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
-LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
- | +++++++++++++++++
+LL | static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
+ | +++++++ +++++++++++++++++
-error[E0106]: missing lifetime specifier
- --> $DIR/missing-lifetime-specifier.rs:35:44
+error[E0106]: missing lifetime specifiers
+ --> $DIR/missing-lifetime-specifier.rs:33:44
|
LL | / thread_local! {
LL | | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
- | | ^ expected named lifetime parameter
-LL | |
-LL | |
+ | | ^ ^ expected 2 lifetime parameters
+ | | |
+ | | expected named lifetime parameter
LL | |
LL | |
LL | | }
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
-error[E0106]: missing lifetime specifiers
- --> $DIR/missing-lifetime-specifier.rs:35:49
+error[E0106]: missing lifetime specifier
+ --> $DIR/missing-lifetime-specifier.rs:47:44
+ |
+LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+ | ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+ |
+LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+ | +++++++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/missing-lifetime-specifier.rs:47:44
|
LL | / thread_local! {
-LL | | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
- | | ^ expected 2 lifetime parameters
-LL | |
+LL | | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+ | | ^ expected named lifetime parameter
LL | |
LL | |
+... |
LL | |
LL | | }
| |_-
|
- = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:43:44
+ --> $DIR/missing-lifetime-specifier.rs:39:44
|
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
| +++++++++
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:43:44
+ --> $DIR/missing-lifetime-specifier.rs:39:44
|
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
| ++++
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:43:44
+ --> $DIR/missing-lifetime-specifier.rs:39:44
|
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
| ++++
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:43:44
+ --> $DIR/missing-lifetime-specifier.rs:39:44
|
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
| ++++
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:43:44
+ --> $DIR/missing-lifetime-specifier.rs:39:44
|
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
| +++++++++
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:51:45
+ --> $DIR/missing-lifetime-specifier.rs:47:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
| +++++++++
-error[E0106]: missing lifetime specifier
- --> $DIR/missing-lifetime-specifier.rs:51:44
- |
-LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
- | ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
- |
-LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
- | ~~~~~~~~
-
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:51:45
+ --> $DIR/missing-lifetime-specifier.rs:47:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = RefCell::new(HashMap::new());
| ++++
-error[E0106]: missing lifetime specifier
- --> $DIR/missing-lifetime-specifier.rs:51:44
- |
-LL | / thread_local! {
-LL | | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
- | | ^ expected named lifetime parameter
-LL | |
-LL | |
-... |
-LL | |
-LL | | }
- | |_-
- |
- = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
-
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:51:45
+ --> $DIR/missing-lifetime-specifier.rs:47:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
| ++++
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:51:45
+ --> $DIR/missing-lifetime-specifier.rs:47:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
| ++++
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:51:45
+ --> $DIR/missing-lifetime-specifier.rs:47:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
| +++++++++
-error: aborting due to 24 previous errors
+error: aborting due to 20 previous errors
Some errors have detailed explanations: E0106, E0107.
For more information about an error, try `rustc --explain E0106`.
struct X<'a>(&'a ());
struct S<'a>(&'a dyn Fn(&X) -> &X);
-//~^ ERROR missing lifetime specifier
-//~| ERROR missing lifetime specifier
+//~^ ERROR missing lifetime specifiers
struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
-//~^ ERROR missing lifetime specifier
-//~| ERROR missing lifetime specifier
+//~^ ERROR missing lifetime specifiers
fn main() {
let x = S(&|x| {
-error[E0106]: missing lifetime specifier
+error[E0106]: missing lifetime specifiers
--> $DIR/missing-lt-for-hrtb.rs:2:32
|
LL | struct S<'a>(&'a dyn Fn(&X) -> &X);
- | -- ^ expected named lifetime parameter
+ | -- ^^ expected named lifetime parameter
+ | |
+ | expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
- = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider making the bound lifetime-generic with a new `'b` lifetime
- |
-LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &'b X);
- | +++++++ ~~~~~ ~~~
-help: consider using the `'a` lifetime
- |
-LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X);
- | ~~~
-
-error[E0106]: missing lifetime specifier
- --> $DIR/missing-lt-for-hrtb.rs:2:33
- |
-LL | struct S<'a>(&'a dyn Fn(&X) -> &X);
- | -- ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
- = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider making the bound lifetime-generic with a new `'b` lifetime
- |
-LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &X<'b>);
- | +++++++ ~~~~~ ~~~~~
help: consider using the `'a` lifetime
|
-LL | struct S<'a>(&'a dyn Fn(&X) -> &X<'a>);
- | ~~~~~
+LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X<'a>);
+ | ++ ++++
-error[E0106]: missing lifetime specifier
- --> $DIR/missing-lt-for-hrtb.rs:5:40
+error[E0106]: missing lifetime specifiers
+ --> $DIR/missing-lt-for-hrtb.rs:4:40
|
LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
- | -- ^ expected named lifetime parameter
+ | -- ^^ expected named lifetime parameter
+ | |
+ | expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
note: these named lifetimes are available to use
- --> $DIR/missing-lt-for-hrtb.rs:5:10
+ --> $DIR/missing-lt-for-hrtb.rs:4:10
|
LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
| ^^ ^^
help: consider using one of the available lifetimes here
|
-LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X);
- | +++++++++
-
-error[E0106]: missing lifetime specifier
- --> $DIR/missing-lt-for-hrtb.rs:5:41
- |
-LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
- | -- ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
-note: these named lifetimes are available to use
- --> $DIR/missing-lt-for-hrtb.rs:5:10
- |
-LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
- | ^^ ^^
+LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X<'lifetime>);
+ | +++++++++ +++++++++++
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0106`.
fn f1() -> &i32 { loop {} }
//~^ ERROR missing lifetime specifier [E0106]
fn f1_() -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
fn f2(a: i32, b: i32) -> &i32 { loop {} }
//~^ ERROR missing lifetime specifier [E0106]
fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
struct S<'a, 'b> { a: &'a i32, b: &'b i32 }
fn f3(s: &S) -> &i32 { loop {} }
//~^ ERROR missing lifetime specifier [E0106]
fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
//~^ ERROR missing lifetime specifier [E0106]
fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} }
//~^ ERROR missing lifetime specifier [E0106]
fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
fn main() {}
help: consider using the `'static` lifetime
|
LL | fn f1() -> &'static i32 { loop {} }
- | ~~~~~~~~
+ | +++++++
-error[E0106]: missing lifetime specifier
+error[E0106]: missing lifetime specifiers
--> $DIR/return-elided-lifetime.rs:8:14
|
LL | fn f1_() -> (&i32, &i32) { loop {} }
- | ^ expected named lifetime parameter
+ | ^ ^ expected named lifetime parameter
+ | |
+ | expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
-LL | fn f1_() -> (&'static i32, &i32) { loop {} }
- | ~~~~~~~~
+LL | fn f1_() -> (&'static i32, &'static i32) { loop {} }
+ | +++++++ +++++++
error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:8:20
- |
-LL | fn f1_() -> (&i32, &i32) { loop {} }
- | ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
- |
-LL | fn f1_() -> (&i32, &'static i32) { loop {} }
- | ~~~~~~~~
-
-error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:12:26
+ --> $DIR/return-elided-lifetime.rs:11:26
|
LL | fn f2(a: i32, b: i32) -> &i32 { loop {} }
| ^ expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
LL | fn f2(a: i32, b: i32) -> &'static i32 { loop {} }
- | ~~~~~~~~
+ | +++++++
-error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:14:28
+error[E0106]: missing lifetime specifiers
+ --> $DIR/return-elided-lifetime.rs:13:28
|
LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
- | ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
-help: consider using the `'static` lifetime
+ | ^ ^ expected named lifetime parameter
+ | |
+ | expected named lifetime parameter
|
-LL | fn f2_(a: i32, b: i32) -> (&'static i32, &i32) { loop {} }
- | ~~~~~~~~
-
-error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:14:34
- |
-LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
- | ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
-LL | fn f2_(a: i32, b: i32) -> (&i32, &'static i32) { loop {} }
- | ~~~~~~~~
+LL | fn f2_(a: i32, b: i32) -> (&'static i32, &'static i32) { loop {} }
+ | +++++++ +++++++
error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:19:17
+ --> $DIR/return-elided-lifetime.rs:17:17
|
LL | fn f3(s: &S) -> &i32 { loop {} }
| -- ^ expected named lifetime parameter
= help: this function's return type contains a borrowed value, but the signature does not say which one of `s`'s 3 lifetimes it is borrowed from
help: consider introducing a named lifetime parameter
|
-LL | fn f3<'a>(s: &'a S) -> &'a i32 { loop {} }
- | ++++ ++ ++
+LL | fn f3<'a>(s: &'a S<'a, 'a>) -> &'a i32 { loop {} }
+ | ++++ ++ ++++++++ ++
-error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:21:26
+error[E0106]: missing lifetime specifiers
+ --> $DIR/return-elided-lifetime.rs:19:26
|
LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
- | -- -- ^ expected named lifetime parameter
+ | -- -- ^ ^ expected named lifetime parameter
+ | |
+ | expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes
help: consider introducing a named lifetime parameter
|
-LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&'a i32, &i32) { loop {} }
- | ++++ ++ ++ ++
+LL | fn f3_<'a>(s: &'a S<'a, 'a>, t: &'a S<'a, 'a>) -> (&'a i32, &'a i32) { loop {} }
+ | ++++ ++ ++++++++ ++ ++++++++ ++ ++
error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:21:32
- |
-LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
- | -- -- ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes
-help: consider introducing a named lifetime parameter
- |
-LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&i32, &'a i32) { loop {} }
- | ++++ ++ ++ ++
-
-error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:25:42
+ --> $DIR/return-elided-lifetime.rs:22:42
|
LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
| ------- ------- ^ expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
+ = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
note: these named lifetimes are available to use
- --> $DIR/return-elided-lifetime.rs:25:7
+ --> $DIR/return-elided-lifetime.rs:22:7
|
LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
| ^^ ^^
LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &'lifetime i32 { loop {} }
| +++++++++
-error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:27:44
- |
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
- | ------- ------- ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
-note: these named lifetimes are available to use
- --> $DIR/return-elided-lifetime.rs:27:8
- |
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
- | ^^ ^^
-help: consider using one of the available lifetimes here
- |
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &i32) { loop {} }
- | +++++++++
-
-error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:27:50
+error[E0106]: missing lifetime specifiers
+ --> $DIR/return-elided-lifetime.rs:24:44
|
LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
- | ------- ------- ^ expected named lifetime parameter
+ | ------- ------- ^ ^ expected named lifetime parameter
+ | |
+ | expected named lifetime parameter
|
- = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
+ = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
note: these named lifetimes are available to use
- --> $DIR/return-elided-lifetime.rs:27:8
+ --> $DIR/return-elided-lifetime.rs:24:8
|
LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
| ^^ ^^
help: consider using one of the available lifetimes here
|
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &'lifetime i32) { loop {} }
- | +++++++++
+LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &'lifetime i32) { loop {} }
+ | +++++++++ +++++++++
error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:31:35
+ --> $DIR/return-elided-lifetime.rs:27:35
|
LL | fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} }
| ------- ---- ^ expected named lifetime parameter
help: consider using the `'a` lifetime
|
LL | fn f5<'a>(a: &'a i32, b: &i32) -> &'a i32 { loop {} }
- | ~~~
-
-error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:33:37
- |
-LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
- | ------- ---- ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
-help: consider using the `'a` lifetime
- |
-LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&'a i32, &i32) { loop {} }
- | ~~~
+ | ++
-error[E0106]: missing lifetime specifier
- --> $DIR/return-elided-lifetime.rs:33:43
+error[E0106]: missing lifetime specifiers
+ --> $DIR/return-elided-lifetime.rs:29:37
|
LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
- | ------- ---- ^ expected named lifetime parameter
+ | ------- ---- ^ ^ expected named lifetime parameter
+ | |
+ | expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
help: consider using the `'a` lifetime
|
-LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &'a i32) { loop {} }
- | ~~~
+LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&'a i32, &'a i32) { loop {} }
+ | ++ ++
-error: aborting due to 15 previous errors
+error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0106`.
help: consider using the `'a` lifetime
|
LL | struct Foo<'a>(&'a usize);
- | ~~~
+ | ++
error[E0106]: missing lifetime specifier
--> $DIR/return-without-lifetime.rs:5:34
help: consider using the `'a` lifetime
|
LL | fn func1<'a>(_arg: &'a Thing) -> &'a () { unimplemented!() }
- | ~~~
+ | ++
error[E0106]: missing lifetime specifier
--> $DIR/return-without-lifetime.rs:7:35
help: consider using the `'a` lifetime
|
LL | fn func2<'a>(_arg: &Thing<'a>) -> &'a () { unimplemented!() }
- | ~~~
+ | ++
error: aborting due to 3 previous errors
| ------ ------ ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
+ = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | let _: dyn for<'a> Foo(&'a isize, &'a usize) -> &'a usize;
+ | +++++++ ++ ++ ++
help: consider introducing a named lifetime parameter
|
LL ~ fn main<'a>() {
struct Foo {
x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier
- //~^ ERROR E0228
}
-fn main() { }
+fn main() {}
LL ~ x: Box<dyn Debug + 'a>,
|
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
- --> $DIR/dyn-trait-underscore-in-struct.rs:9:12
- |
-LL | x: Box<dyn Debug + '_>,
- | ^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0106, E0228.
-For more information about an error, try `rustc --explain E0106`.
+For more information about this error, try `rustc --explain E0106`.
+error[E0106]: missing lifetime specifier
+ --> $DIR/underscore-lifetime-binders.rs:2:17
+ |
+LL | struct Baz<'a>(&'_ &'a u8);
+ | ^^ expected named lifetime parameter
+ |
+help: consider using the `'a` lifetime
+ |
+LL | struct Baz<'a>(&'a &'a u8);
+ | ~~
+
error[E0637]: `'_` cannot be used here
--> $DIR/underscore-lifetime-binders.rs:4:8
|
LL | fn meh() -> Box<dyn for<'_> Meh<'_>>
| ^^ `'_` is a reserved lifetime name
-error[E0106]: missing lifetime specifier
- --> $DIR/underscore-lifetime-binders.rs:2:17
- |
-LL | struct Baz<'a>(&'_ &'a u8);
- | ^^ expected named lifetime parameter
- |
-help: consider using the `'a` lifetime
- |
-LL | struct Baz<'a>(&'a &'a u8);
- | ~~
-
error[E0106]: missing lifetime specifier
--> $DIR/underscore-lifetime-binders.rs:10:33
|
-Subproject commit d8d30a75376f78bb0fabe3d28ee9d87aa8035309
+Subproject commit 85b500ccad8cd0b63995fd94a03ddd4b83f7905b
use rustc_hir::FnRetTy::Return;
use rustc_hir::{
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
- ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, LifetimeParamKind, ParamName, PolyTraitRef,
- PredicateOrigin, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
+ ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin,
+ TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter as middle_nested_filter;
+use rustc_middle::ty::TyCtxt;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, Ident, Symbol};
enum RefLt {
Unnamed,
Static,
- Named(Symbol),
+ Named(LocalDefId),
}
fn check_fn_inner<'tcx>(
// level of the current item.
// check named LTs
- let allowed_lts = allowed_lts_from(named_generics);
+ let allowed_lts = allowed_lts_from(cx.tcx, named_generics);
// these will collect all the lifetimes for references in arg/return types
let mut input_visitor = RefVisitor::new(cx);
return false;
}
- if allowed_lts
- .intersection(
- &input_visitor
- .nested_elision_site_lts
- .iter()
- .chain(output_visitor.nested_elision_site_lts.iter())
- .cloned()
- .filter(|v| matches!(v, RefLt::Named(_)))
- .collect(),
- )
- .next()
- .is_some()
- {
- return false;
- }
-
let input_lts = input_visitor.lts;
let output_lts = output_visitor.lts;
}
}
+ // check for higher-ranked trait bounds
+ if !input_visitor.nested_elision_site_lts.is_empty() || !output_visitor.nested_elision_site_lts.is_empty() {
+ let allowed_lts: FxHashSet<_> = allowed_lts
+ .iter()
+ .filter_map(|lt| match lt {
+ RefLt::Named(def_id) => Some(cx.tcx.item_name(def_id.to_def_id())),
+ _ => None,
+ })
+ .collect();
+ for lt in input_visitor.nested_elision_site_lts {
+ if let RefLt::Named(def_id) = lt {
+ if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
+ return false;
+ }
+ }
+ }
+ for lt in output_visitor.nested_elision_site_lts {
+ if let RefLt::Named(def_id) = lt {
+ if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
+ return false;
+ }
+ }
+ }
+ }
+
// no input lifetimes? easy case!
if input_lts.is_empty() {
false
}
}
-fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
+fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
let mut allowed_lts = FxHashSet::default();
for par in named_generics.iter() {
- if let GenericParamKind::Lifetime {
- kind: LifetimeParamKind::Explicit,
- } = par.kind
- {
- allowed_lts.insert(RefLt::Named(par.name.ident().name));
+ if let GenericParamKind::Lifetime { .. } = par.kind {
+ allowed_lts.insert(RefLt::Named(tcx.hir().local_def_id(par.hir_id)));
}
}
allowed_lts.insert(RefLt::Unnamed);
self.lts.push(RefLt::Unnamed);
} else if lt.is_elided() {
self.lts.push(RefLt::Unnamed);
+ } else if let LifetimeName::Param(def_id, _) = lt.name {
+ self.lts.push(RefLt::Named(def_id));
} else {
- self.lts.push(RefLt::Named(lt.name.ident().name));
+ self.lts.push(RefLt::Unnamed);
}
} else {
self.lts.push(RefLt::Unnamed);
TyKind::OpaqueDef(item, bounds) => {
let map = self.cx.tcx.hir();
let item = map.item(item);
+ let len = self.lts.len();
walk_item(self, item);
- walk_ty(self, ty);
+ self.lts.truncate(len);
self.lts.extend(bounds.iter().filter_map(|bound| match bound {
- GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)),
+ GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id, _) = l.name {
+ RefLt::Named(def_id)
+ } else {
+ RefLt::Unnamed
+ }),
_ => None,
}));
},
}
return;
},
- _ => (),
+ _ => walk_ty(self, ty),
}
- walk_ty(self, ty);
}
}
return true;
}
// if the bounds define new lifetimes, they are fine to occur
- let allowed_lts = allowed_lts_from(pred.bound_generic_params);
+ let allowed_lts = allowed_lts_from(cx.tcx, pred.bound_generic_params);
// now walk the bounds
for bound in pred.bounds.iter() {
walk_param_bound(&mut visitor, bound);
return;
}
- // These appear to be broken in mdbook right now?
- if fragment.starts_with('-') {
- return;
- }
-
parse_ids(&mut target_ids.borrow_mut(), &pretty_path, target_source, report);
if target_ids.borrow().contains(*fragment) {
-Subproject commit 963f08b702caf7a06eed564312933ec50dd07f54
+Subproject commit b938529fb8ed8f7b5b374282ffc3ffa74c313111
("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
("cranelift-entity", "Apache-2.0 WITH LLVM-exception"),
("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"),
+ ("cranelift-isle", "Apache-2.0 WITH LLVM-exception"),
("cranelift-jit", "Apache-2.0 WITH LLVM-exception"),
("cranelift-module", "Apache-2.0 WITH LLVM-exception"),
("cranelift-native", "Apache-2.0 WITH LLVM-exception"),
("cranelift-object", "Apache-2.0 WITH LLVM-exception"),
("mach", "BSD-2-Clause"),
- ("regalloc", "Apache-2.0 WITH LLVM-exception"),
+ ("regalloc2", "Apache-2.0 WITH LLVM-exception"),
("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
];
];
const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
+ "ahash",
"anyhow",
"ar",
"autocfg",
"bitflags",
+ "byteorder",
"cfg-if",
"cranelift-bforest",
"cranelift-codegen",
"cranelift-codegen-shared",
"cranelift-entity",
"cranelift-frontend",
+ "cranelift-isle",
"cranelift-jit",
"cranelift-module",
"cranelift-native",
"cranelift-object",
"crc32fast",
+ "fxhash",
+ "getrandom",
"gimli",
"hashbrown",
"indexmap",
"memchr",
"object",
"once_cell",
- "regalloc",
+ "regalloc2",
"region",
- "rustc-hash",
+ "slice-group-by",
"smallvec",
"target-lexicon",
+ "version_check",
+ "wasi",
"winapi",
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",