Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2024-04-24 05:04:52 +00:00
commit 7e968351aa
326 changed files with 4301 additions and 2171 deletions

View File

@ -44,7 +44,7 @@ impl Subdiagnostic for InvalidAbiReason {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: F,
_: &F,
) {
#[allow(rustc::untranslatable_diagnostic)]
diag.note(self.0);

View File

@ -382,7 +382,7 @@ impl Subdiagnostic for EmptyLabelManySpans {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: F,
_: &F,
) {
diag.span_labels(self.0, "");
}
@ -751,7 +751,7 @@ impl Subdiagnostic for StableFeature {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: F,
_: &F,
) {
diag.arg("name", self.name);
diag.arg("since", self.since);

View File

@ -69,7 +69,8 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
let kind = match self.kind {
mir::BorrowKind::Shared => "",
mir::BorrowKind::Fake => "fake ",
mir::BorrowKind::Fake(mir::FakeBorrowKind::Deep) => "fake ",
mir::BorrowKind::Fake(mir::FakeBorrowKind::Shallow) => "fake shallow ",
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
// FIXME: differentiate `TwoPhaseBorrow`
mir::BorrowKind::Mut {

View File

@ -17,9 +17,9 @@ use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place,
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
VarBindingForm,
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
TerminatorKind, VarBindingForm,
};
use rustc_middle::ty::{
self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt,
@ -1486,7 +1486,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let first_borrow_desc;
let mut err = match (gen_borrow_kind, issued_borrow.kind) {
(
BorrowKind::Shared,
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
) => {
first_borrow_desc = "mutable ";
@ -1504,7 +1504,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
(
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
BorrowKind::Shared,
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
) => {
first_borrow_desc = "immutable ";
let mut err = self.cannot_reborrow_already_borrowed(
@ -1566,7 +1566,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
}
(BorrowKind::Mut { .. }, BorrowKind::Fake) => {
(BorrowKind::Mut { .. }, BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
if let Some(immutable_section_description) =
self.classify_immutable_section(issued_borrow.assigned_place)
{
@ -1629,7 +1629,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
)
}
(BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {
(
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },
) => {
first_borrow_desc = "first ";
self.cannot_reborrow_already_uniquely_borrowed(
span,
@ -1659,8 +1662,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
)
}
(BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Fake)
| (BorrowKind::Fake, BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) => {
(
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
BorrowKind::Shared | BorrowKind::Fake(_),
)
| (
BorrowKind::Fake(FakeBorrowKind::Shallow),
BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_),
) => {
unreachable!()
}
};
@ -3572,7 +3581,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let loan_span = loan_spans.args_or_use();
let descr_place = self.describe_any_place(place.as_ref());
if loan.kind == BorrowKind::Fake {
if let BorrowKind::Fake(_) = loan.kind {
if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
let mut err = self.cannot_mutate_in_immutable_section(
span,

View File

@ -654,7 +654,7 @@ impl UseSpans<'_> {
match kind {
Some(kd) => match kd {
rustc_middle::mir::BorrowKind::Shared
| rustc_middle::mir::BorrowKind::Fake => {
| rustc_middle::mir::BorrowKind::Fake(_) => {
CaptureVarKind::Immut { kind_span: capture_kind_span }
}

View File

@ -1056,18 +1056,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Control::Continue
}
(Read(_), BorrowKind::Shared | BorrowKind::Fake)
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
Control::Continue
}
(Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
| (
Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
BorrowKind::Mut { .. },
) => Control::Continue,
(Reservation(_), BorrowKind::Fake | BorrowKind::Shared) => {
(Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
// This used to be a future compatibility warning (to be
// disallowed on NLL). See rust-lang/rust#56254
Control::Continue
}
(Write(WriteKind::Move), BorrowKind::Fake) => {
(Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
// Handled by initialization checks.
Control::Continue
}
@ -1175,10 +1176,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
match rvalue {
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
let access_kind = match bk {
BorrowKind::Fake => {
BorrowKind::Fake(FakeBorrowKind::Shallow) => {
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
}
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
(Deep, Read(ReadKind::Borrow(bk)))
}
BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if allow_two_phase_borrow(bk) {
@ -1197,7 +1200,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
flow_state,
);
let action = if bk == BorrowKind::Fake {
let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
InitializationRequiringAction::MatchOn
} else {
InitializationRequiringAction::Borrow
@ -1557,7 +1560,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// only mutable borrows should be 2-phase
assert!(match borrow.kind {
BorrowKind::Shared | BorrowKind::Fake => false,
BorrowKind::Shared | BorrowKind::Fake(_) => false,
BorrowKind::Mut { .. } => true,
});
@ -2122,14 +2125,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| WriteKind::Replace
| WriteKind::StorageDeadOrDrop
| WriteKind::MutableBorrow(BorrowKind::Shared)
| WriteKind::MutableBorrow(BorrowKind::Fake),
| WriteKind::MutableBorrow(BorrowKind::Fake(_)),
)
| Write(
WriteKind::Move
| WriteKind::Replace
| WriteKind::StorageDeadOrDrop
| WriteKind::MutableBorrow(BorrowKind::Shared)
| WriteKind::MutableBorrow(BorrowKind::Fake),
| WriteKind::MutableBorrow(BorrowKind::Fake(_)),
) => {
if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
&& !self.has_buffered_diags()
@ -2153,7 +2156,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return false;
}
Read(
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake)
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
| ReadKind::Copy,
) => {
// Access authorized

View File

@ -55,7 +55,7 @@ use crate::Overlap;
use crate::{AccessDepth, Deep, Shallow};
use rustc_hir as hir;
use rustc_middle::mir::{
Body, BorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,
Body, BorrowKind, FakeBorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,
};
use rustc_middle::ty::{self, TyCtxt};
use std::cmp::max;
@ -271,10 +271,10 @@ fn place_components_conflict<'tcx>(
// If the second example, where we did, then we still know
// that the borrow can access a *part* of our place that
// our access cares about, so we still have a conflict.
if borrow_kind == BorrowKind::Fake
if borrow_kind == BorrowKind::Fake(FakeBorrowKind::Shallow)
&& borrow_place.projection.len() < access_place.projection.len()
{
debug!("borrow_conflicts_with_place: fake borrow");
debug!("borrow_conflicts_with_place: shallow borrow");
false
} else {
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");

View File

@ -1,6 +1,8 @@
use rustc_data_structures::graph::dominators::Dominators;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
use rustc_middle::mir::{
self, BasicBlock, Body, FakeBorrowKind, Location, NonDivergingIntrinsic, Place, Rvalue,
};
use rustc_middle::mir::{BorrowKind, Mutability, Operand};
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::mir::{Statement, StatementKind};
@ -239,10 +241,12 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
match rvalue {
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
let access_kind = match bk {
BorrowKind::Fake => {
BorrowKind::Fake(FakeBorrowKind::Shallow) => {
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
}
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
(Deep, Read(ReadKind::Borrow(bk)))
}
BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if allow_two_phase_borrow(bk) {
@ -357,8 +361,11 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
// have already taken the reservation
}
(Read(_), BorrowKind::Fake | BorrowKind::Shared)
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
(Read(_), BorrowKind::Fake(_) | BorrowKind::Shared)
| (
Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
BorrowKind::Mut { .. },
) => {
// Reads don't invalidate shared or shallow borrows
}
@ -403,7 +410,7 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
// only mutable borrows should be 2-phase
assert!(match borrow.kind {
BorrowKind::Shared | BorrowKind::Fake => false,
BorrowKind::Shared | BorrowKind::Fake(_) => false,
BorrowKind::Mut { .. } => true,
});

View File

@ -601,7 +601,7 @@ impl Subdiagnostic for FormatUnusedArg {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: F,
f: &F,
) {
diag.arg("named", self.named);
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());

View File

@ -4,9 +4,9 @@ version = 3
[[package]]
name = "ahash"
version = "0.8.7"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"once_cell",
@ -16,9 +16,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.75"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
[[package]]
name = "arbitrary"
@ -34,9 +34,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.14.0"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "cfg-if"
@ -46,18 +46,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cranelift-bforest"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a535eb1cf5a6003197dc569320c40c1cb2d2f97ef5d5348eebf067f20957381"
checksum = "79b27922a6879b5b5361d0a084cb0b1941bf109a98540addcb932da13b68bed4"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11b5066db32cec1492573827183af2142d2d88fe85a83cfc9e73f0f63d3788d4"
checksum = "304c455b28bf56372729acb356afbb55d622f2b0f2f7837aa5e57c138acaac4d"
dependencies = [
"bumpalo",
"cranelift-bforest",
@ -67,7 +67,7 @@ dependencies = [
"cranelift-entity",
"cranelift-isle",
"gimli",
"hashbrown 0.14.0",
"hashbrown 0.14.3",
"log",
"regalloc2",
"smallvec",
@ -76,39 +76,39 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64942e5774308e835fbad4dd25f253105412c90324631910e1ec27963147bddb"
checksum = "1653c56b99591d07f67c5ca7f9f25888948af3f4b97186bff838d687d666f613"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c39c33db9a86dd6d8d04166a10c53deb477aeea3500eaaefca682e4eda9bb986"
checksum = "f5b6a9cf6b6eb820ee3f973a0db313c05dc12d370f37b4fe9630286e1672573f"
[[package]]
name = "cranelift-control"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b7fc4937613aea3156a0538800a17bf56f345a5da2e79ae3df58488c93d867f"
checksum = "d9d06e6bf30075fb6bed9e034ec046475093392eea1aff90eb5c44c4a033d19a"
dependencies = [
"arbitrary",
]
[[package]]
name = "cranelift-entity"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f85575e79a153ce1ddbfb7fe1813519b4bfe1eb200cc9c8353b45ad123ae4d36"
checksum = "29be04f931b73cdb9694874a295027471817f26f26d2f0ebe5454153176b6e3a"
[[package]]
name = "cranelift-frontend"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbc31d6c0ab2249fe0c21e988256b42f5f401ab2673b4fc40076c82a698bdfb9"
checksum = "a07fd7393041d7faa2f37426f5dc7fc04003b70988810e8c063beefeff1cd8f9"
dependencies = [
"cranelift-codegen",
"log",
@ -118,15 +118,15 @@ dependencies = [
[[package]]
name = "cranelift-isle"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc14f37e3314c0e4c53779c2f46753bf242efff76ee9473757a1fff3b495ad37"
checksum = "f341d7938caa6dff8149dac05bb2b53fc680323826b83b4cf175ab9f5139a3c9"
[[package]]
name = "cranelift-jit"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfdd1942f3233176a68c285380dbc84ff0440246a1bce308611c0a385b56ab18"
checksum = "42733555e06433f1461570e09dbd756dafc228b4dac75c597cdbdc518de07522"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -139,14 +139,14 @@ dependencies = [
"region",
"target-lexicon",
"wasmtime-jit-icache-coherence",
"windows-sys 0.52.0",
"windows-sys",
]
[[package]]
name = "cranelift-module"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121b2b5a16912554a1b9aace75b9b21eca49f28e33cbfbad4786dd9bc5361a5c"
checksum = "84950af02bb85f3da764d53a953b43bb29a732e793d4fe24637a61591be9a024"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -155,9 +155,9 @@ dependencies = [
[[package]]
name = "cranelift-native"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ea5375f76ab31f9800a23fb2b440810286a6f669a3eb467cdd7ff255ea64268"
checksum = "82af6066e6448d26eeabb7aa26a43f7ff79f8217b06bade4ee6ef230aecc8880"
dependencies = [
"cranelift-codegen",
"libc",
@ -166,9 +166,9 @@ dependencies = [
[[package]]
name = "cranelift-object"
version = "0.106.0"
version = "0.107.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f34e04419ab41661e973d90a73aa7b12771455394dae7a69b101a9b7e7589db7"
checksum = "00af56107039ed150391df6f753298c7b08f2b6a2e0727d216b5fa599d684d8b"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -181,9 +181,9 @@ dependencies = [
[[package]]
name = "crc32fast"
version = "1.3.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [
"cfg-if",
]
@ -222,21 +222,21 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.14.0"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
dependencies = [
"ahash",
]
[[package]]
name = "indexmap"
version = "2.0.0"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown 0.14.0",
"hashbrown 0.14.3",
]
[[package]]
@ -247,19 +247,19 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "libloading"
version = "0.8.1"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
"windows-targets",
]
[[package]]
name = "log"
version = "0.4.20"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "mach"
@ -272,42 +272,42 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.6.3"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "object"
version = "0.32.0"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
checksum = "d8dd6c0cdf9429bce006e1362bfce61fa1bfd8c898a643ed8d2b471934701d3d"
dependencies = [
"crc32fast",
"hashbrown 0.14.0",
"hashbrown 0.14.3",
"indexmap",
"memchr",
]
[[package]]
name = "once_cell"
version = "1.18.0"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "proc-macro2"
version = "1.0.75"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708"
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
@ -369,9 +369,9 @@ checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
[[package]]
name = "smallvec"
version = "1.11.0"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "stable_deref_trait"
@ -381,9 +381,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "syn"
version = "2.0.47"
version = "2.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1726efe18f42ae774cc644f330953a5e7b3c3003d3edcecf18850fe9d4dd9afb"
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
dependencies = [
"proc-macro2",
"quote",
@ -410,13 +410,13 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasmtime-jit-icache-coherence"
version = "19.0.0"
version = "20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2796e4b4989db62899d2117e1e0258b839d088c044591b14e3a0396e7b3ae53a"
checksum = "7a9f93a3289057b26dc75eb84d6e60d7694f7d169c7c09597495de6e016a13ff"
dependencies = [
"cfg-if",
"libc",
"windows-sys 0.52.0",
"windows-sys",
]
[[package]]
@ -441,137 +441,78 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.0",
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]]
name = "zerocopy"

View File

@ -8,15 +8,15 @@ crate-type = ["dylib"]
[dependencies]
# These have to be in sync with each other
cranelift-codegen = { version = "0.106.0", default-features = false, features = ["std", "unwind", "all-arch"] }
cranelift-frontend = { version = "0.106.0" }
cranelift-module = { version = "0.106.0" }
cranelift-native = { version = "0.106.0" }
cranelift-jit = { version = "0.106.0", optional = true }
cranelift-object = { version = "0.106.0" }
cranelift-codegen = { version = "0.107.0", default-features = false, features = ["std", "unwind", "all-arch"] }
cranelift-frontend = { version = "0.107.0" }
cranelift-module = { version = "0.107.0" }
cranelift-native = { version = "0.107.0" }
cranelift-jit = { version = "0.107.0", optional = true }
cranelift-object = { version = "0.107.0" }
target-lexicon = "0.12.0"
gimli = { version = "0.28", default-features = false, features = ["write"]}
object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
object = { version = "0.33", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
indexmap = "2.0.0"
libloading = { version = "0.8.0", optional = true }

View File

@ -43,7 +43,13 @@ pub(crate) fn run(
let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs);
cmd.arg("--");
cmd.arg("--pairs");
cmd.args(pairs);
cmd.args(
if cfg!(not(any(target_os = "macos", all(target_os = "windows", target_env = "msvc")))) {
&pairs[..]
} else {
&pairs[..2]
},
);
cmd.arg("--add-rustc-codegen-backend");
match cg_clif_dylib {
CodegenBackend::Local(path) => {

View File

@ -290,7 +290,7 @@ pub(crate) fn run_tests(
&& !skip_tests.contains(&"testsuite.extended_sysroot");
if run_base_sysroot || run_extended_sysroot {
let mut target_compiler = build_sysroot::build_sysroot(
let target_compiler = build_sysroot::build_sysroot(
dirs,
channel,
sysroot_kind,
@ -299,11 +299,8 @@ pub(crate) fn run_tests(
rustup_toolchain_name,
target_triple.clone(),
);
// Rust's build system denies a couple of lints that trigger on several of the test
// projects. Changing the code to fix them is not worth it, so just silence all lints.
target_compiler.rustflags.push("--cap-lints=allow".to_owned());
let runner = TestRunner::new(
let mut runner = TestRunner::new(
dirs.clone(),
target_compiler,
use_unstable_features,
@ -319,6 +316,9 @@ pub(crate) fn run_tests(
}
if run_extended_sysroot {
// Rust's build system denies a couple of lints that trigger on several of the test
// projects. Changing the code to fix them is not worth it, so just silence all lints.
runner.target_compiler.rustflags.push("--cap-lints=allow".to_owned());
runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
} else {
eprintln!("[SKIP] extended_sysroot tests");

View File

@ -1,4 +1,5 @@
#![feature(start, core_intrinsics, alloc_error_handler, lang_items)]
#![allow(internal_features)]
#![no_std]
extern crate alloc;

View File

@ -80,7 +80,6 @@ mod platform {
extern "system" {
fn GetProcessHeap() -> HANDLE;
fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
fn GetLastError() -> DWORD;
}
@ -111,7 +110,7 @@ mod platform {
allocate_with_flags(layout, HEAP_ZERO_MEMORY)
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
let header = get_header(ptr);
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());

View File

@ -149,7 +149,7 @@ pub fn array_as_slice(arr: &[u8; 3]) -> &[u8] {
arr
}
pub unsafe fn use_ctlz_nonzero(a: u16) -> u16 {
pub unsafe fn use_ctlz_nonzero(a: u16) -> u32 {
intrinsics::ctlz_nonzero(a)
}

View File

@ -5,7 +5,7 @@
// Test that the simd_f{min,max} intrinsics produce the correct results.
#![feature(repr_simd, core_intrinsics)]
#![allow(non_camel_case_types)]
#![allow(internal_features, non_camel_case_types)]
#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]

View File

@ -627,7 +627,7 @@ pub mod intrinsics {
pub fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
pub fn transmute<T, U>(e: T) -> U;
pub fn ctlz_nonzero<T>(x: T) -> T;
pub fn ctlz_nonzero<T>(x: T) -> u32;
#[rustc_safe_intrinsic]
pub fn needs_drop<T: ?::Sized>() -> bool;
#[rustc_safe_intrinsic]

View File

@ -1,4 +1,5 @@
#![feature(start, core_intrinsics, lang_items)]
#![allow(internal_features)]
#![no_std]
#[cfg_attr(unix, link(name = "c"))]

View File

@ -4,7 +4,9 @@
#[cfg(target_arch = "aarch64")]
use std::arch::aarch64::*;
#[cfg(target_arch = "aarch64")]
use std::mem::transmute;
#[cfg(target_arch = "aarch64")]
use std::simd::*;
#[cfg(target_arch = "aarch64")]

View File

@ -7,6 +7,7 @@
tuple_trait,
unboxed_closures
)]
#![allow(internal_features)]
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;

View File

@ -11,7 +11,7 @@ diff --git a/src/report.rs b/src/report.rs
index eeec614..f582867 100644
--- a/src/report.rs
+++ b/src/report.rs
@@ -48,6 +48,12 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl
@@ -48,6 +48,15 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl
//
// THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
@ -19,6 +19,9 @@ index eeec614..f582867 100644
+ if cfg!(all(target_os = "windows", target_env = "gnu")) && test.test_name == "ui128" {
+ result.run = Link;
+ result.check = Pass(Link);
+ } else if test.test_name == "ui128" {
+ result.run == Check;
+ result.check = Pass(Check);
+ }
+
// END OF VENDOR RESERVED AREA

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2024-04-11"
channel = "nightly-2024-04-23"
components = ["rust-src", "rustc-dev", "llvm-tools"]

View File

@ -7,11 +7,13 @@ mod returning;
use std::borrow::Cow;
use cranelift_codegen::ir::SigRef;
use cranelift_codegen::isa::CallConv;
use cranelift_module::ModuleError;
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::TypeVisitableExt;
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_session::Session;
use rustc_span::source_map::Spanned;

View File

@ -2,12 +2,14 @@
use cranelift_codegen::ir::UserFuncName;
use cranelift_codegen::CodegenError;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use cranelift_module::ModuleError;
use rustc_ast::InlineAsmOptions;
use rustc_index::IndexVec;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::TypeVisitableExt;
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
use crate::constant::ConstantCx;
@ -823,7 +825,13 @@ fn codegen_stmt<'tcx>(
};
let data = codegen_operand(fx, data);
let meta = codegen_operand(fx, meta);
let ptr_val = CValue::pointer_from_data_and_meta(data, meta, layout);
assert!(data.layout().ty.is_unsafe_ptr());
assert!(layout.ty.is_unsafe_ptr());
let ptr_val = if meta.layout().is_zst() {
data.cast_pointer_to(layout)
} else {
CValue::by_val_pair(data.load_scalar(fx), meta.load_scalar(fx), layout)
};
lval.write_cvalue(fx, ptr_val);
}
Rvalue::Aggregate(ref kind, ref operands) => {

View File

@ -1,8 +1,10 @@
use cranelift_codegen::isa::TargetFrontendConfig;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use rustc_index::IndexVec;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
};
use rustc_middle::ty::TypeFoldable;
use rustc_span::source_map::Spanned;
use rustc_target::abi::call::FnAbi;
use rustc_target::abi::{Integer, Primitive};

View File

@ -137,18 +137,23 @@ pub(crate) fn codegen_const_value<'tcx>(
let alloc_id = prov.alloc_id();
let base_addr = match fx.tcx.global_alloc(alloc_id) {
GlobalAlloc::Memory(alloc) => {
let data_id = data_id_for_alloc_id(
&mut fx.constants_cx,
fx.module,
alloc_id,
alloc.inner().mutability,
);
let local_data_id =
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("{:?}", alloc_id));
if alloc.inner().len() == 0 {
assert_eq!(offset, Size::ZERO);
fx.bcx.ins().iconst(fx.pointer_type, alloc.inner().align.bytes() as i64)
} else {
let data_id = data_id_for_alloc_id(
&mut fx.constants_cx,
fx.module,
alloc_id,
alloc.inner().mutability,
);
let local_data_id =
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("{:?}", alloc_id));
}
fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}
fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}
GlobalAlloc::Function(instance) => {
let func_id = crate::abi::import_function(fx.tcx, fx.module, instance);

View File

@ -19,7 +19,7 @@ use rustc_codegen_ssa::debuginfo::type_names;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefIdMap;
use rustc_session::Session;
use rustc_span::{SourceFileHash, StableSourceFileId};
use rustc_span::{FileNameDisplayPreference, SourceFileHash, StableSourceFileId};
use rustc_target::abi::call::FnAbi;
pub(crate) use self::emit::{DebugReloc, DebugRelocName};

View File

@ -2,7 +2,7 @@ use cranelift_module::{DataId, FuncId};
use cranelift_object::ObjectProduct;
use gimli::SectionId;
use object::write::{Relocation, StandardSegment};
use object::{RelocationEncoding, SectionKind};
use object::{RelocationEncoding, RelocationFlags, SectionKind};
use rustc_data_structures::fx::FxHashMap;
use crate::debuginfo::{DebugReloc, DebugRelocName};
@ -72,9 +72,11 @@ impl WriteDebugInfo for ObjectProduct {
Relocation {
offset: u64::from(reloc.offset),
symbol,
kind: reloc.kind,
encoding: RelocationEncoding::Generic,
size: reloc.size * 8,
flags: RelocationFlags::Generic {
kind: reloc.kind,
encoding: RelocationEncoding::Generic,
size: reloc.size * 8,
},
addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
},
)

View File

@ -6,6 +6,7 @@ use std::ffi::CString;
use std::os::raw::{c_char, c_int};
use std::sync::{mpsc, Mutex, OnceLock};
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use cranelift_jit::{JITBuilder, JITModule};
use rustc_codegen_ssa::CrateInfo;
use rustc_middle::mir::mono::MonoItem;

View File

@ -2,6 +2,7 @@
use std::fmt::Write;
use cranelift_codegen::isa::CallConv;
use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_span::sym;
use rustc_target::asm::*;
@ -785,9 +786,9 @@ fn call_inline_asm<'tcx>(
for (offset, place) in outputs {
let ty = if place.layout().ty.is_simd() {
let (lane_count, lane_type) = place.layout().ty.simd_size_and_type(fx.tcx);
fx.clif_type(lane_type).unwrap().by(lane_count.try_into().unwrap()).unwrap()
asm_clif_type(fx, lane_type).unwrap().by(lane_count.try_into().unwrap()).unwrap()
} else {
fx.clif_type(place.layout().ty).unwrap()
asm_clif_type(fx, place.layout().ty).unwrap()
};
let value = stack_slot.offset(fx, i32::try_from(offset.bytes()).unwrap().into()).load(
fx,
@ -797,3 +798,24 @@ fn call_inline_asm<'tcx>(
place.write_cvalue(fx, CValue::by_val(value, place.layout()));
}
}
fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option<types::Type> {
match ty.kind() {
// Adapted from https://github.com/rust-lang/rust/blob/f3c66088610c1b80110297c2d9a8b5f9265b013f/compiler/rustc_hir_analysis/src/check/intrinsicck.rs#L136-L151
ty::Adt(adt, args) if Some(adt.did()) == fx.tcx.lang_items().maybe_uninit() => {
let fields = &adt.non_enum_variant().fields;
let ty = fields[FieldIdx::from_u32(1)].ty(fx.tcx, args);
let ty::Adt(ty, args) = ty.kind() else {
unreachable!("expected first field of `MaybeUninit` to be an ADT")
};
assert!(
ty.is_manually_drop(),
"expected first field of `MaybeUninit` to be `ManuallyDrop`"
);
let fields = &ty.non_enum_variant().fields;
let ty = fields[FieldIdx::ZERO].ty(fx.tcx, args);
fx.clif_type(ty)
}
_ => fx.clif_type(ty),
}
}

View File

@ -26,6 +26,7 @@ use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Symbol};
pub(crate) use self::llvm::codegen_llvm_intrinsic_call;
use crate::cast::clif_intcast;
use crate::prelude::*;
fn bug_on_incorrect_arg_count(intrinsic: impl std::fmt::Display) -> ! {
@ -627,7 +628,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
// FIXME trap on `ctlz_nonzero` with zero arg.
let res = fx.bcx.ins().clz(val);
let res = CValue::by_val(res, arg.layout());
let res = clif_intcast(fx, res, types::I32, false);
let res = CValue::by_val(res, ret.layout());
ret.write_cvalue(fx, res);
}
sym::cttz | sym::cttz_nonzero => {
@ -636,7 +638,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
// FIXME trap on `cttz_nonzero` with zero arg.
let res = fx.bcx.ins().ctz(val);
let res = CValue::by_val(res, arg.layout());
let res = clif_intcast(fx, res, types::I32, false);
let res = CValue::by_val(res, ret.layout());
ret.write_cvalue(fx, res);
}
sym::ctpop => {
@ -644,7 +647,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
let val = arg.load_scalar(fx);
let res = fx.bcx.ins().popcnt(val);
let res = CValue::by_val(res, arg.layout());
let res = clif_intcast(fx, res, types::I32, false);
let res = CValue::by_val(res, ret.layout());
ret.write_cvalue(fx, res);
}
sym::bitreverse => {

View File

@ -87,21 +87,17 @@ mod prelude {
AbiParam, Block, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, StackSlot,
StackSlotData, StackSlotKind, TrapCode, Type, Value,
};
pub(crate) use cranelift_codegen::isa::{self, CallConv};
pub(crate) use cranelift_codegen::Context;
pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
pub(crate) use cranelift_module::{self, DataDescription, FuncId, Linkage, Module};
pub(crate) use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
pub(crate) use rustc_index::Idx;
pub(crate) use rustc_middle::bug;
pub(crate) use rustc_middle::mir::{self, *};
pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout};
pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
pub(crate) use rustc_middle::ty::{
self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
TypeFoldable, TypeVisitableExt, UintTy,
self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, UintTy,
};
pub(crate) use rustc_span::{FileNameDisplayPreference, Span};
pub(crate) use rustc_span::Span;
pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT};
pub(crate) use crate::abi::*;
@ -261,7 +257,7 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple {
}
}
fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn isa::TargetIsa + 'static> {
fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn TargetIsa + 'static> {
use target_lexicon::BinaryFormat;
let target_triple = crate::target_triple(sess);

View File

@ -1,3 +1,4 @@
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use rustc_hir::LangItem;
use rustc_middle::ty::AssocKind;
use rustc_middle::ty::GenericArg;

View File

@ -2,6 +2,7 @@
use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::immediates::Offset32;
use cranelift_frontend::Variable;
use rustc_middle::ty::FnSig;
use crate::prelude::*;
@ -94,23 +95,6 @@ impl<'tcx> CValue<'tcx> {
CValue(CValueInner::ByValPair(value, extra), layout)
}
/// For `AggregateKind::RawPtr`, create a pointer from its parts.
///
/// Panics if the `layout` is not a raw pointer.
pub(crate) fn pointer_from_data_and_meta(
data: CValue<'tcx>,
meta: CValue<'tcx>,
layout: TyAndLayout<'tcx>,
) -> CValue<'tcx> {
assert!(layout.ty.is_unsafe_ptr());
let inner = match (data.0, meta.0) {
(CValueInner::ByVal(p), CValueInner::ByVal(m)) => CValueInner::ByValPair(p, m),
(p @ CValueInner::ByVal(_), CValueInner::ByRef(..)) if meta.1.is_zst() => p,
_ => bug!("RawPtr operands {data:?} {meta:?}"),
};
CValue(inner, layout)
}
pub(crate) fn layout(&self) -> TyAndLayout<'tcx> {
self.1
}

View File

@ -153,9 +153,10 @@ fn array_as_slice(arr: &[u8; 3]) -> &[u8] {
arr
}
unsafe fn use_ctlz_nonzero(a: u16) -> u16 {
intrinsics::ctlz_nonzero(a)
}
// FIXME: fix the intrinsic implementation to work with the new ->u32 signature
// unsafe fn use_ctlz_nonzero(a: u16) -> u32 {
// intrinsics::ctlz_nonzero(a)
// }
fn ptr_as_usize(ptr: *const u8) -> usize {
ptr as usize

View File

@ -593,7 +593,7 @@ pub mod intrinsics {
pub fn min_align_of_val<T: ?Sized>(val: *const T) -> usize;
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
pub fn transmute<T, U>(e: T) -> U;
pub fn ctlz_nonzero<T>(x: T) -> T;
pub fn ctlz_nonzero<T>(x: T) -> u32;
#[rustc_safe_intrinsic]
pub fn needs_drop<T: ?Sized>() -> bool;
#[rustc_safe_intrinsic]

View File

@ -315,25 +315,32 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
Some((width, signed)) => match name {
sym::ctlz | sym::cttz => {
let y = self.const_bool(false);
self.call_intrinsic(
let ret = self.call_intrinsic(
&format!("llvm.{name}.i{width}"),
&[args[0].immediate(), y],
)
);
self.intcast(ret, llret_ty, false)
}
sym::ctlz_nonzero => {
let y = self.const_bool(true);
let llvm_name = &format!("llvm.ctlz.i{width}");
self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
self.intcast(ret, llret_ty, false)
}
sym::cttz_nonzero => {
let y = self.const_bool(true);
let llvm_name = &format!("llvm.cttz.i{width}");
self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
self.intcast(ret, llret_ty, false)
}
sym::ctpop => {
let ret = self.call_intrinsic(
&format!("llvm.ctpop.i{width}"),
&[args[0].immediate()],
);
self.intcast(ret, llret_ty, false)
}
sym::ctpop => self.call_intrinsic(
&format!("llvm.ctpop.i{width}"),
&[args[0].immediate()],
),
sym::bswap => {
if width == 8 {
args[0].immediate() // byte swap a u8/i8 is just a no-op
@ -355,6 +362,10 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
// rotate = funnel shift with first two args the same
let llvm_name =
&format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width);
// llvm expects shift to be the same type as the values, but rust always uses `u32`
let raw_shift = self.intcast(raw_shift, self.val_ty(val), false);
self.call_intrinsic(llvm_name, &[val, val, raw_shift])
}
sym::saturating_add | sym::saturating_sub => {

View File

@ -82,12 +82,6 @@ const_eval_double_storage_live =
const_eval_dyn_call_not_a_method =
`dyn` call trying to call something that is not a method
const_eval_dyn_call_vtable_mismatch =
`dyn` call on a pointer whose vtable does not match its type
const_eval_dyn_star_call_vtable_mismatch =
`dyn*` call on a pointer whose vtable does not match its type
const_eval_error = {$error_kind ->
[static] could not evaluate static initializer
[const] evaluation of constant value failed
@ -192,6 +186,8 @@ const_eval_invalid_uninit_bytes_unknown =
const_eval_invalid_vtable_pointer =
using {$pointer} as vtable pointer but it does not point to a vtable
const_eval_invalid_vtable_trait =
using vtable for trait `{$vtable_trait}` but trait `{$expected_trait}` was expected
const_eval_live_drop =
destructor of `{$dropped_ty}` cannot be evaluated at compile-time
@ -401,9 +397,6 @@ const_eval_unterminated_c_string =
const_eval_unwind_past_top =
unwinding past the topmost frame of the stack
const_eval_upcast_mismatch =
upcast on a pointer whose vtable does not match its type
## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`.
## (We'd love to sort this differently to make that more clear but tidy won't let us...)
const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant
@ -450,6 +443,7 @@ const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, bu
const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object
const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$ref_trait}`, but encountered `{$vtable_trait}`
const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
const_eval_validation_null_box = {$front_matter}: encountered a null box

View File

@ -46,6 +46,9 @@ impl<'mir, 'tcx: 'mir> interpret::Machine<'mir, 'tcx> for DummyMachine {
type MemoryKind = !;
const PANIC_ON_ALLOC_FAIL: bool = true;
// We want to just eval random consts in the program, so `eval_mir_const` can fail.
const ALL_CONSTS_ARE_PRECHECKED: bool = false;
#[inline(always)]
fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
false // no reason to enforce alignment

View File

@ -498,6 +498,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
InvalidTag(_) => const_eval_invalid_tag,
InvalidFunctionPointer(_) => const_eval_invalid_function_pointer,
InvalidVTablePointer(_) => const_eval_invalid_vtable_pointer,
InvalidVTableTrait { .. } => const_eval_invalid_vtable_trait,
InvalidStr(_) => const_eval_invalid_str,
InvalidUninitBytes(None) => const_eval_invalid_uninit_bytes_unknown,
InvalidUninitBytes(Some(_)) => const_eval_invalid_uninit_bytes,
@ -537,6 +538,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
| DeadLocal
| UninhabitedEnumVariantWritten(_)
| UninhabitedEnumVariantRead(_) => {}
BoundsCheckFailed { len, index } => {
diag.arg("len", len);
diag.arg("index", index);
@ -544,6 +546,13 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
diag.arg("pointer", ptr);
}
InvalidVTableTrait { expected_trait, vtable_trait } => {
diag.arg("expected_trait", expected_trait.to_string());
diag.arg(
"vtable_trait",
vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("<trivial>")),
);
}
PointerUseAfterFree(alloc_id, msg) => {
diag.arg("alloc_id", alloc_id)
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
@ -634,6 +643,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant,
Uninit { .. } => const_eval_validation_uninit,
InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr,
InvalidMetaWrongTrait { .. } => const_eval_validation_invalid_vtable_trait,
InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
const_eval_validation_invalid_box_slice_meta
}
@ -773,6 +783,13 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
DanglingPtrNoProvenance { pointer, .. } => {
err.arg("pointer", pointer);
}
InvalidMetaWrongTrait { expected_trait: ref_trait, vtable_trait } => {
err.arg("ref_trait", ref_trait.to_string());
err.arg(
"vtable_trait",
vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("<trivial>")),
);
}
NullPtr { .. }
| PtrToStatic { .. }
| ConstRefToMutable

View File

@ -393,6 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let val = self.read_immediate(src)?;
if data_a.principal() == data_b.principal() {
// A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables.
// (But currently mismatching vtables violate the validity invariant so UB is triggered anyway.)
return self.write_immediate(*val, dest);
}
let (old_data, old_vptr) = val.to_scalar_pair();
@ -400,7 +401,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let old_vptr = old_vptr.to_pointer(self)?;
let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?;
if old_trait != data_a.principal() {
throw_ub_custom!(fluent::const_eval_upcast_mismatch);
throw_ub!(InvalidVTableTrait {
expected_trait: data_a,
vtable_trait: old_trait,
});
}
let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)

View File

@ -822,15 +822,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.stack_mut().push(frame);
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
if M::POST_MONO_CHECKS {
for &const_ in &body.required_consts {
let c = self
.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| {
err.emit_note(*self.tcx);
err
})?;
}
for &const_ in &body.required_consts {
let c =
self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| {
err.emit_note(*self.tcx);
err
})?;
}
// done
@ -1181,8 +1179,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| {
let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| {
// FIXME: somehow this is reachable even when POST_MONO_CHECKS is on.
// Are we not always populating `required_consts`?
if M::ALL_CONSTS_ARE_PRECHECKED && !matches!(err, ErrorHandled::TooGeneric(..)) {
// Looks like the const is not captued by `required_consts`, that's bad.
bug!("interpret const eval failure of {val:?} which is not in required_consts");
}
err.emit_note(*ecx.tcx);
err
})?;

View File

@ -173,7 +173,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let ty = instance_args.type_at(0);
let layout = self.layout_of(ty)?;
let val = self.read_scalar(&args[0])?;
let out_val = self.numeric_intrinsic(intrinsic_name, val, layout)?;
let out_val = self.numeric_intrinsic(intrinsic_name, val, layout, dest.layout)?;
self.write_scalar(out_val, dest)?;
}
sym::saturating_add | sym::saturating_sub => {
@ -200,12 +201,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::rotate_left | sym::rotate_right => {
// rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
// rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
let layout = self.layout_of(instance_args.type_at(0))?;
let layout_val = self.layout_of(instance_args.type_at(0))?;
let val = self.read_scalar(&args[0])?;
let val_bits = val.to_bits(layout.size)?;
let val_bits = val.to_bits(layout_val.size)?;
let layout_raw_shift = self.layout_of(self.tcx.types.u32)?;
let raw_shift = self.read_scalar(&args[1])?;
let raw_shift_bits = raw_shift.to_bits(layout.size)?;
let width_bits = u128::from(layout.size.bits());
let raw_shift_bits = raw_shift.to_bits(layout_raw_shift.size)?;
let width_bits = u128::from(layout_val.size.bits());
let shift_bits = raw_shift_bits % width_bits;
let inv_shift_bits = (width_bits - shift_bits) % width_bits;
let result_bits = if intrinsic_name == sym::rotate_left {
@ -213,8 +217,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else {
(val_bits >> shift_bits) | (val_bits << inv_shift_bits)
};
let truncated_bits = self.truncate(result_bits, layout);
let result = Scalar::from_uint(truncated_bits, layout.size);
let truncated_bits = self.truncate(result_bits, layout_val);
let result = Scalar::from_uint(truncated_bits, layout_val.size);
self.write_scalar(result, dest)?;
}
sym::copy => {
@ -472,6 +476,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
name: Symbol,
val: Scalar<M::Provenance>,
layout: TyAndLayout<'tcx>,
ret_layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, Scalar<M::Provenance>> {
assert!(layout.ty.is_integral(), "invalid type for numeric intrinsic: {}", layout.ty);
let bits = val.to_bits(layout.size)?;
@ -483,11 +488,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
sym::ctlz | sym::ctlz_nonzero => u128::from(bits.leading_zeros()) - extra,
sym::cttz | sym::cttz_nonzero => u128::from((bits << extra).trailing_zeros()) - extra,
sym::bswap => (bits << extra).swap_bytes(),
sym::bitreverse => (bits << extra).reverse_bits(),
sym::bswap => {
assert_eq!(layout, ret_layout);
(bits << extra).swap_bytes()
}
sym::bitreverse => {
assert_eq!(layout, ret_layout);
(bits << extra).reverse_bits()
}
_ => bug!("not a numeric intrinsic: {}", name),
};
Ok(Scalar::from_uint(bits_out, layout.size))
Ok(Scalar::from_uint(bits_out, ret_layout.size))
}
pub fn exact_div(

View File

@ -140,8 +140,9 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// Should the machine panic on allocation failures?
const PANIC_ON_ALLOC_FAIL: bool;
/// Should post-monomorphization checks be run when a stack frame is pushed?
const POST_MONO_CHECKS: bool = true;
/// Determines whether `eval_mir_constant` can never fail because all required consts have
/// already been checked before.
const ALL_CONSTS_ARE_PRECHECKED: bool = true;
/// Whether memory accesses should be alignment-checked.
fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;

View File

@ -1020,16 +1020,20 @@ where
pub(super) fn unpack_dyn_trait(
&self,
mplace: &MPlaceTy<'tcx, M::Provenance>,
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer<Option<M::Provenance>>)> {
assert!(
matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
"`unpack_dyn_trait` only makes sense on `dyn*` types"
);
let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
let (ty, _) = self.get_ptr_vtable(vtable)?;
let layout = self.layout_of(ty)?;
let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?;
if expected_trait.principal() != vtable_trait {
throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
}
// This is a kind of transmute, from a place with unsized type and metadata to
// a place with sized type and no metadata.
let layout = self.layout_of(ty)?;
let mplace =
MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout };
Ok((mplace, vtable))
@ -1040,6 +1044,7 @@ where
pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
&self,
val: &P,
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)> {
assert!(
matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
@ -1048,10 +1053,12 @@ where
let data = self.project_field(val, 0)?;
let vtable = self.project_field(val, 1)?;
let vtable = self.read_pointer(&vtable.to_op(self)?)?;
let (ty, _) = self.get_ptr_vtable(vtable)?;
let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?;
if expected_trait.principal() != vtable_trait {
throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
}
// `data` is already the right thing but has the wrong type. So we transmute it.
let layout = self.layout_of(ty)?;
// `data` is already the right thing but has the wrong type. So we transmute it, by
// projecting with offset 0.
let data = data.transmute(layout, self)?;
Ok((data, vtable))
}

View File

@ -803,11 +803,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let (vptr, dyn_ty, adjusted_receiver) = if let ty::Dynamic(data, _, ty::DynStar) =
receiver_place.layout.ty.kind()
{
let (recv, vptr) = self.unpack_dyn_star(&receiver_place)?;
let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
if dyn_trait != data.principal() {
throw_ub_custom!(fluent::const_eval_dyn_star_call_vtable_mismatch);
}
let (recv, vptr) = self.unpack_dyn_star(&receiver_place, data)?;
let (dyn_ty, _dyn_trait) = self.get_ptr_vtable(vptr)?;
(vptr, dyn_ty, recv.ptr())
} else {
@ -829,7 +826,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
if dyn_trait != data.principal() {
throw_ub_custom!(fluent::const_eval_dyn_call_vtable_mismatch);
throw_ub!(InvalidVTableTrait {
expected_trait: data,
vtable_trait: dyn_trait,
});
}
// It might be surprising that we use a pointer as the receiver even if this
@ -939,13 +939,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let place = self.force_allocation(place)?;
let place = match place.layout.ty.kind() {
ty::Dynamic(_, _, ty::Dyn) => {
ty::Dynamic(data, _, ty::Dyn) => {
// Dropping a trait object. Need to find actual drop fn.
self.unpack_dyn_trait(&place)?.0
self.unpack_dyn_trait(&place, data)?.0
}
ty::Dynamic(_, _, ty::DynStar) => {
ty::Dynamic(data, _, ty::DynStar) => {
// Dropping a `dyn*`. Need to find actual drop fn.
self.unpack_dyn_star(&place)?.0
self.unpack_dyn_star(&place, data)?.0
}
_ => {
debug_assert_eq!(

View File

@ -339,16 +339,22 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
) -> InterpResult<'tcx> {
let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
match tail.kind() {
ty::Dynamic(_, _, ty::Dyn) => {
ty::Dynamic(data, _, ty::Dyn) => {
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
// Make sure it is a genuine vtable pointer.
let (_ty, _trait) = try_validation!(
let (_dyn_ty, dyn_trait) = try_validation!(
self.ecx.get_ptr_vtable(vtable),
self.path,
Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) =>
InvalidVTablePtr { value: format!("{vtable}") }
);
// FIXME: check if the type/trait match what ty::Dynamic says?
// Make sure it is for the right trait.
if dyn_trait != data.principal() {
throw_validation_failure!(
self.path,
InvalidMetaWrongTrait { expected_trait: data, vtable_trait: dyn_trait }
);
}
}
ty::Slice(..) | ty::Str => {
let _len = meta.unwrap_meta().to_target_usize(self.ecx)?;
@ -933,7 +939,16 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
}
}
_ => {
self.walk_value(op)?; // default handler
// default handler
try_validation!(
self.walk_value(op),
self.path,
// It's not great to catch errors here, since we can't give a very good path,
// but it's better than ICEing.
Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => {
InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait }
},
);
}
}

View File

@ -88,22 +88,22 @@ pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
// Special treatment for special types, where the (static) layout is not sufficient.
match *ty.kind() {
// If it is a trait object, switch to the real type that was used to create it.
ty::Dynamic(_, _, ty::Dyn) => {
ty::Dynamic(data, _, ty::Dyn) => {
// Dyn types. This is unsized, and the actual dynamic type of the data is given by the
// vtable stored in the place metadata.
// unsized values are never immediate, so we can assert_mem_place
let op = v.to_op(self.ecx())?;
let dest = op.assert_mem_place();
let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?.0;
let inner_mplace = self.ecx().unpack_dyn_trait(&dest, data)?.0;
trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout);
// recurse with the inner type
return self.visit_field(v, 0, &inner_mplace.into());
}
ty::Dynamic(_, _, ty::DynStar) => {
ty::Dynamic(data, _, ty::DynStar) => {
// DynStar types. Very different from a dyn type (but strangely part of the
// same variant in `TyKind`): These are pairs where the 2nd component is the
// vtable, and the first component is the data (which must be ptr-sized).
let data = self.ecx().unpack_dyn_star(v)?.0;
let data = self.ecx().unpack_dyn_star(v, data)?.0;
return self.visit_field(v, 0, &data);
}
// Slices do not need special handling here: they have `Array` field

View File

@ -414,7 +414,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
BorrowKind::Shared => {
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
}
BorrowKind::Fake => {
BorrowKind::Fake(_) => {
PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow)
}
BorrowKind::Mut { .. } => {
@ -487,7 +487,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
}
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake, place)
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place)
| Rvalue::AddressOf(Mutability::Not, place) => {
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
self.ccx,

View File

@ -105,7 +105,7 @@ where
fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
match kind {
mir::BorrowKind::Mut { .. } => true,
mir::BorrowKind::Shared | mir::BorrowKind::Fake => {
mir::BorrowKind::Shared | mir::BorrowKind::Fake(_) => {
self.shared_borrow_allows_mutation(place)
}
}

View File

@ -965,7 +965,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
},
Rvalue::Ref(_, BorrowKind::Fake, _) => {
Rvalue::Ref(_, BorrowKind::Fake(_), _) => {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,

View File

@ -6,7 +6,7 @@ Erroneous code example:
#![feature(lang_items)]
#[lang = "cookie"]
fn cookie() -> ! { // error: definition of an unknown language item: `cookie`
fn cookie() -> ! { // error: definition of an unknown lang item: `cookie`
loop {}
}
```

View File

@ -177,7 +177,7 @@ where
{
/// Add a subdiagnostic to an existing diagnostic.
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
self.add_to_diag_with(diag, |_, m| m);
self.add_to_diag_with(diag, &|_, m| m);
}
/// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
@ -185,7 +185,7 @@ where
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: F,
f: &F,
);
}
@ -1197,7 +1197,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
dcx: &crate::DiagCtxt,
subdiagnostic: impl Subdiagnostic,
) -> &mut Self {
subdiagnostic.add_to_diag_with(self, |diag, msg| {
subdiagnostic.add_to_diag_with(self, &|diag, msg| {
let args = diag.args.iter();
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
dcx.eagerly_translate(msg, args)

View File

@ -227,6 +227,36 @@ impl IntoDiagArg for rustc_lint_defs::Level {
}
}
impl<Id> IntoDiagArg for hir::def::Res<Id> {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::Borrowed(self.descr()))
}
}
impl IntoDiagArg for DiagLocation {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::from(self.to_string()))
}
}
impl IntoDiagArg for Backtrace {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::from(self.to_string()))
}
}
impl IntoDiagArg for Level {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::from(self.to_string()))
}
}
impl IntoDiagArg for type_ir::ClosureKind {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(self.as_str().into())
}
}
#[derive(Clone)]
pub struct DiagSymbolList(Vec<Symbol>);
@ -244,12 +274,6 @@ impl IntoDiagArg for DiagSymbolList {
}
}
impl<Id> IntoDiagArg for hir::def::Res<Id> {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::Borrowed(self.descr()))
}
}
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutErrors<'_> {
fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> {
match self {
@ -302,7 +326,7 @@ impl Subdiagnostic for SingleLabelManySpans {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: F,
_: &F,
) {
diag.span_labels(self.spans, self.label);
}
@ -316,24 +340,6 @@ pub struct ExpectedLifetimeParameter {
pub count: usize,
}
impl IntoDiagArg for DiagLocation {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::from(self.to_string()))
}
}
impl IntoDiagArg for Backtrace {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::from(self.to_string()))
}
}
impl IntoDiagArg for Level {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::from(self.to_string()))
}
}
#[derive(Subdiagnostic)]
#[suggestion(errors_indicate_anonymous_lifetime, code = "{suggestion}", style = "verbose")]
pub struct IndicateAnonymousLifetime {
@ -343,8 +349,10 @@ pub struct IndicateAnonymousLifetime {
pub suggestion: String,
}
impl IntoDiagArg for type_ir::ClosureKind {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(self.as_str().into())
}
#[derive(Subdiagnostic)]
pub struct ElidedLifetimeInPathSubdiag {
#[subdiagnostic]
pub expected: ExpectedLifetimeParameter,
#[subdiagnostic]
pub indicate: Option<IndicateAnonymousLifetime>,
}

View File

@ -40,8 +40,8 @@ pub use diagnostic::{
SubdiagMessageOp, Subdiagnostic,
};
pub use diagnostic_impls::{
DiagArgFromDisplay, DiagSymbolList, ExpectedLifetimeParameter, IndicateAnonymousLifetime,
SingleLabelManySpans,
DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
IndicateAnonymousLifetime, SingleLabelManySpans,
};
pub use emitter::ColorConfig;
pub use rustc_error_messages::{
@ -1911,27 +1911,24 @@ impl Level {
}
// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
pub fn add_elided_lifetime_in_path_suggestion<G: EmissionGuarantee>(
pub fn elided_lifetime_in_path_suggestion(
source_map: &SourceMap,
diag: &mut Diag<'_, G>,
n: usize,
path_span: Span,
incl_angl_brckt: bool,
insertion_span: Span,
) {
diag.subdiagnostic(diag.dcx, ExpectedLifetimeParameter { span: path_span, count: n });
if !source_map.is_span_accessible(insertion_span) {
// Do not try to suggest anything if generated by a proc-macro.
return;
}
let anon_lts = vec!["'_"; n].join(", ");
let suggestion =
if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
) -> ElidedLifetimeInPathSubdiag {
let expected = ExpectedLifetimeParameter { span: path_span, count: n };
// Do not try to suggest anything if generated by a proc-macro.
let indicate = source_map.is_span_accessible(insertion_span).then(|| {
let anon_lts = vec!["'_"; n].join(", ");
let suggestion =
if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
diag.subdiagnostic(
diag.dcx,
IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion },
);
IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
});
ElidedLifetimeInPathSubdiag { expected, indicate }
}
pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(

View File

@ -798,7 +798,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// ==========================================================================
gated!(
lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, EncodeCrossCrate::No, lang_items,
"language items are subject to change",
"lang items are subject to change",
),
rustc_attr!(
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,

View File

@ -644,13 +644,49 @@ impl<'hir> Generics<'hir> {
})
}
pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option<Span> {
/// Returns a suggestable empty span right after the "final" bound of the generic parameter.
///
/// If that bound needs to be wrapped in parentheses to avoid ambiguity with
/// subsequent bounds, it also returns an empty span for an open parenthesis
/// as the second component.
///
/// E.g., adding `+ 'static` after `Fn() -> dyn Future<Output = ()>` or
/// `Fn() -> &'static dyn Debug` requires parentheses:
/// `Fn() -> (dyn Future<Output = ()>) + 'static` and
/// `Fn() -> &'static (dyn Debug) + 'static`, respectively.
pub fn bounds_span_for_suggestions(
&self,
param_def_id: LocalDefId,
) -> Option<(Span, Option<Span>)> {
self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
|bound| {
// We include bounds that come from a `#[derive(_)]` but point at the user's code,
// as we use this method to get a span appropriate for suggestions.
let bs = bound.span();
bs.can_be_used_for_suggestions().then(|| bs.shrink_to_hi())
let span_for_parentheses = if let Some(trait_ref) = bound.trait_ref()
&& let [.., segment] = trait_ref.path.segments
&& segment.args().parenthesized == GenericArgsParentheses::ParenSugar
&& let [binding] = segment.args().bindings
&& let TypeBindingKind::Equality { term: Term::Ty(ret_ty) } = binding.kind
&& let ret_ty = ret_ty.peel_refs()
&& let TyKind::TraitObject(
_,
_,
TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar,
) = ret_ty.kind
&& ret_ty.span.can_be_used_for_suggestions()
{
Some(ret_ty.span)
} else {
None
};
span_for_parentheses.map_or_else(
|| {
// We include bounds that come from a `#[derive(_)]` but point at the user's code,
// as we use this method to get a span appropriate for suggestions.
let bs = bound.span();
bs.can_be_used_for_suggestions().then(|| (bs.shrink_to_hi(), None))
},
|span| Some((span.shrink_to_hi(), Some(span.shrink_to_lo()))),
)
},
)
}

View File

@ -1,4 +1,4 @@
//! Defines language items.
//! Defines lang items.
//!
//! Language items are items that represent concepts intrinsic to the language
//! itself. Examples are:
@ -16,7 +16,7 @@ use rustc_macros::HashStable_Generic;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
/// All of the language items, defined or not.
/// All of the lang items, defined or not.
/// Defined lang items can come from the current crate or its dependencies.
#[derive(HashStable_Generic, Debug)]
pub struct LanguageItems {
@ -57,7 +57,7 @@ macro_rules! language_item_table {
) => {
enum_from_u32! {
/// A representation of all the valid language items in Rust.
/// A representation of all the valid lang items in Rust.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum LangItem {
$(
@ -177,7 +177,7 @@ language_item_table! {
CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1);
DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1);
// language items relating to transmutability
// lang items relating to transmutability
TransmuteOpts, sym::transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0);
TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(2);
@ -304,7 +304,7 @@ language_item_table! {
OwnedBox, sym::owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1);
GlobalAlloc, sym::global_alloc_ty, global_alloc_ty, Target::Struct, GenericRequirement::None;
// Experimental language item for Miri
// Experimental lang item for Miri
PtrUnique, sym::ptr_unique, ptr_unique, Target::Struct, GenericRequirement::Exact(1);
PhantomData, sym::phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1);

View File

@ -43,16 +43,6 @@ impl<'tcx> Bounds<'tcx> {
trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
polarity: ty::PredicatePolarity,
) {
self.push_trait_bound_inner(tcx, trait_ref, span, polarity);
}
fn push_trait_bound_inner(
&mut self,
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
polarity: ty::PredicatePolarity,
) {
let clause = (
trait_ref

View File

@ -10,11 +10,10 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::Node;
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
use rustc_infer::traits::Obligation;
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
@ -24,10 +23,10 @@ use rustc_middle::ty::{
};
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_target::abi::FieldIdx;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _};
use rustc_type_ir::fold::TypeFoldable;
use std::cell::LazyCell;
@ -1715,55 +1714,31 @@ fn opaque_type_cycle_error(
err.emit()
}
// FIXME(@lcnr): This should not be computed per coroutine, but instead once for
// each typeck root.
pub(super) fn check_coroutine_obligations(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
) -> Result<(), ErrorGuaranteed> {
debug_assert!(tcx.is_coroutine(def_id.to_def_id()));
debug_assert!(!tcx.is_typeck_child(def_id.to_def_id()));
let typeck = tcx.typeck(def_id);
let param_env = tcx.param_env(typeck.hir_owner.def_id);
let typeck_results = tcx.typeck(def_id);
let param_env = tcx.param_env(def_id);
let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id];
debug!(?coroutine_interior_predicates);
debug!(?typeck_results.coroutine_stalled_predicates);
let infcx = tcx
.infer_ctxt()
// typeck writeback gives us predicates with their regions erased.
// As borrowck already has checked lifetimes, we do not need to do it again.
.ignoring_regions()
// Bind opaque types to type checking root, as they should have been checked by borrowck,
// but may show up in some cases, like when (root) obligations are stalled in the new solver.
.with_opaque_type_inference(typeck.hir_owner.def_id)
.with_opaque_type_inference(def_id)
.build();
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);
for (predicate, cause) in coroutine_interior_predicates {
let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
let ocx = ObligationCtxt::new(&infcx);
for (predicate, cause) in &typeck_results.coroutine_stalled_predicates {
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, *predicate));
}
if (tcx.features().unsized_locals || tcx.features().unsized_fn_params)
&& let Some(coroutine) = tcx.mir_coroutine_witnesses(def_id)
{
for field_ty in coroutine.field_tys.iter() {
fulfillment_cx.register_bound(
&infcx,
param_env,
field_ty.ty,
tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)),
ObligationCause::new(
field_ty.source_info.span,
def_id,
ObligationCauseCode::SizedCoroutineInterior(def_id),
),
);
}
}
let errors = fulfillment_cx.select_all_or_error(&infcx);
let errors = ocx.select_all_or_error();
debug!(?errors);
if !errors.is_empty() {
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));

View File

@ -412,13 +412,11 @@ pub fn check_intrinsic_type(
(1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
}
sym::ctpop
| sym::ctlz
| sym::ctlz_nonzero
| sym::cttz
| sym::cttz_nonzero
| sym::bswap
| sym::bitreverse => (1, 0, vec![param(0)], param(0)),
sym::ctpop | sym::ctlz | sym::ctlz_nonzero | sym::cttz | sym::cttz_nonzero => {
(1, 0, vec![param(0)], tcx.types.u32)
}
sym::bswap | sym::bitreverse => (1, 0, vec![param(0)], param(0)),
sym::three_way_compare => {
(1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(Some(span)))
@ -461,7 +459,7 @@ pub fn check_intrinsic_type(
(1, 0, vec![param(0), param(0)], param(0))
}
sym::unchecked_shl | sym::unchecked_shr => (2, 0, vec![param(0), param(1)], param(0)),
sym::rotate_left | sym::rotate_right => (1, 0, vec![param(0), param(0)], param(0)),
sym::rotate_left | sym::rotate_right => (1, 0, vec![param(0), tcx.types.u32], param(0)),
sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => {
(1, 0, vec![param(0), param(0)], param(0))
}
@ -535,7 +533,7 @@ pub fn check_intrinsic_type(
sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) {
Some((va_list_ref_ty, _)) => (0, 0, vec![va_list_ref_ty], Ty::new_unit(tcx)),
None => bug!("`va_list` language item needed for C-variadic intrinsics"),
None => bug!("`va_list` lang item needed for C-variadic intrinsics"),
},
sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) {
@ -543,12 +541,12 @@ pub fn check_intrinsic_type(
let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty);
(0, 0, vec![va_list_ptr_ty, va_list_ref_ty], Ty::new_unit(tcx))
}
None => bug!("`va_list` language item needed for C-variadic intrinsics"),
None => bug!("`va_list` lang item needed for C-variadic intrinsics"),
},
sym::va_arg => match mk_va_list_ty(hir::Mutability::Mut) {
Some((va_list_ref_ty, _)) => (1, 0, vec![va_list_ref_ty], param(0)),
None => bug!("`va_list` language item needed for C-variadic intrinsics"),
None => bug!("`va_list` lang item needed for C-variadic intrinsics"),
},
sym::nontemporal_store => {

View File

@ -17,6 +17,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::traits::FulfillmentError;
use rustc_middle::query::Key;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, suggest_constraining_type_param};
use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{Binder, TraitRef};
@ -1200,12 +1201,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// Emits an error regarding forbidden type binding associations
pub fn prohibit_assoc_item_binding(
tcx: TyCtxt<'_>,
span: Span,
segment: Option<(&hir::PathSegment<'_>, Span)>,
binding: &hir::TypeBinding<'_>,
segment: Option<(DefId, &hir::PathSegment<'_>, Span)>,
) -> ErrorGuaranteed {
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
span,
fn_trait_expansion: if let Some((segment, span)) = segment
let mut err = tcx.dcx().create_err(AssocTypeBindingNotAllowed {
span: binding.span,
fn_trait_expansion: if let Some((_, segment, span)) = segment
&& segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
{
Some(ParenthesizedFnTraitExpansion {
@ -1215,7 +1216,109 @@ pub fn prohibit_assoc_item_binding(
} else {
None
},
})
});
// Emit a suggestion to turn the assoc item binding into a generic arg
// if the relevant item has a generic param whose name matches the binding name;
// otherwise suggest the removal of the binding.
if let Some((def_id, segment, _)) = segment
&& segment.args().parenthesized == hir::GenericArgsParentheses::No
&& let hir::TypeBindingKind::Equality { term } = binding.kind
{
// Suggests removal of the offending binding
let suggest_removal = |e: &mut Diag<'_>| {
let bindings = segment.args().bindings;
let args = segment.args().args;
let binding_span = binding.span;
// Compute the span to remove based on the position
// of the binding. We do that as follows:
// 1. Find the index of the binding in the list of bindings
// 2. Locate the spans preceding and following the binding.
// If it's the first binding the preceding span would be
// that of the last arg
// 3. Using this information work out whether the span
// to remove will start from the end of the preceding span,
// the start of the next span or will simply be the
// span encomassing everything within the generics brackets
let Some(binding_index) = bindings.iter().position(|b| b.hir_id == binding.hir_id)
else {
bug!("a type binding exists but its HIR ID not found in generics");
};
let preceding_span = if binding_index > 0 {
Some(bindings[binding_index - 1].span)
} else {
args.last().map(|a| a.span())
};
let next_span = if binding_index < bindings.len() - 1 {
Some(bindings[binding_index + 1].span)
} else {
None
};
let removal_span = match (preceding_span, next_span) {
(Some(prec), _) => binding_span.with_lo(prec.hi()),
(None, Some(next)) => binding_span.with_hi(next.lo()),
(None, None) => {
let Some(generics_span) = segment.args().span_ext() else {
bug!("a type binding exists but generic span is empty");
};
generics_span
}
};
// Now emit the suggestion
if let Ok(suggestion) = tcx.sess.source_map().span_to_snippet(removal_span) {
e.span_suggestion_verbose(
removal_span,
"consider removing this type binding",
suggestion,
Applicability::MaybeIncorrect,
);
}
};
// Suggest replacing the associated item binding with a generic argument.
// i.e., replacing `<..., T = A, ...>` with `<..., A, ...>`.
let suggest_direct_use = |e: &mut Diag<'_>, sp: Span| {
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sp) {
e.span_suggestion_verbose(
binding.span,
format!("to use `{snippet}` as a generic argument specify it directly"),
snippet,
Applicability::MaybeIncorrect,
);
}
};
// Check if the type has a generic param with the
// same name as the assoc type name in type binding
let generics = tcx.generics_of(def_id);
let matching_param =
generics.params.iter().find(|p| p.name.as_str() == binding.ident.as_str());
// Now emit the appropriate suggestion
if let Some(matching_param) = matching_param {
match (&matching_param.kind, term) {
(GenericParamDefKind::Type { .. }, hir::Term::Ty(ty)) => {
suggest_direct_use(&mut err, ty.span);
}
(GenericParamDefKind::Const { .. }, hir::Term::Const(c)) => {
let span = tcx.hir().span(c.hir_id);
suggest_direct_use(&mut err, span);
}
_ => suggest_removal(&mut err),
}
} else {
suggest_removal(&mut err);
}
}
err.emit()
}
pub(crate) fn fn_trait_to_string(

View File

@ -454,7 +454,7 @@ pub(crate) fn check_generic_arg_count(
if gen_pos != GenericArgPosition::Type
&& let Some(b) = gen_args.bindings.first()
{
prohibit_assoc_item_binding(tcx, b.span, None);
prohibit_assoc_item_binding(tcx, b, None);
}
let explicit_late_bound =

View File

@ -323,7 +323,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
ty::BoundConstness::NotConst,
);
if let Some(b) = item_segment.args().bindings.first() {
prohibit_assoc_item_binding(self.tcx(), b.span, Some((item_segment, span)));
prohibit_assoc_item_binding(self.tcx(), b, Some((def_id, item_segment, span)));
}
args
}
@ -620,7 +620,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
ty::BoundConstness::NotConst,
);
if let Some(b) = item_segment.args().bindings.first() {
prohibit_assoc_item_binding(self.tcx(), b.span, Some((item_segment, span)));
prohibit_assoc_item_binding(self.tcx(), b, Some((item_def_id, item_segment, span)));
}
args
}
@ -765,7 +765,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
constness,
);
if let Some(b) = trait_segment.args().bindings.first() {
prohibit_assoc_item_binding(self.tcx(), b.span, Some((trait_segment, span)));
prohibit_assoc_item_binding(self.tcx(), b, Some((trait_def_id, trait_segment, span)));
}
ty::TraitRef::new(self.tcx(), trait_def_id, generic_args)
}
@ -1544,7 +1544,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
for segment in segments {
// Only emit the first error to avoid overloading the user with error messages.
if let Some(b) = segment.args().bindings.first() {
return Err(prohibit_assoc_item_binding(self.tcx(), b.span, None));
return Err(prohibit_assoc_item_binding(self.tcx(), b, None));
}
}

View File

@ -889,7 +889,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
[candidate] => format!(
"the method of the same name on {} `{}`",
match candidate.kind {
probe::CandidateKind::InherentImplCandidate(..) => "the inherent impl for",
probe::CandidateKind::InherentImplCandidate(_) => "the inherent impl for",
_ => "trait",
},
self.tcx.def_path_str(candidate.item.container_id(self.tcx))

View File

@ -191,7 +191,7 @@ impl Subdiagnostic for TypeMismatchFruTypo {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
diag.arg("expr", self.expr.as_deref().unwrap_or("NONE"));
@ -370,7 +370,7 @@ impl Subdiagnostic for RemoveSemiForCoerce {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
let mut multispan: MultiSpan = self.semi.into();
multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr);
@ -546,7 +546,7 @@ impl rustc_errors::Subdiagnostic for CastUnknownPointerSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: F,
f: &F,
) {
match self {
CastUnknownPointerSub::To(span) => {

View File

@ -750,6 +750,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
}
}
} else if let PatKind::Deref(subpattern) = pat.kind {
// A deref pattern is a bit special: the binding mode of its inner bindings
// determines whether to borrow *at the level of the deref pattern* rather than
// borrowing the bound place (since that inner place is inside the temporary that
// stores the result of calling `deref()`/`deref_mut()` so can't be captured).
let mutable = mc.typeck_results.pat_has_ref_mut_binding(subpattern);
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
let bk = ty::BorrowKind::from_mutbl(mutability);
delegate.borrow(place, discr_place.hir_id, bk);
}
}));
}

View File

@ -588,12 +588,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
obligations
.extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx));
let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause)).collect();
debug!(?obligations);
self.typeck_results
.borrow_mut()
.coroutine_interior_predicates
.insert(expr_def_id, obligations);
let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause));
self.typeck_results.borrow_mut().coroutine_stalled_predicates.extend(obligations);
}
}

View File

@ -23,7 +23,7 @@ use rustc_hir::{
};
use rustc_hir_analysis::collect::suggest_impl_trait;
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_infer::traits::{self};
use rustc_infer::traits;
use rustc_middle::lint::in_external_macro;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::print::with_no_trimmed_paths;

View File

@ -66,7 +66,7 @@ use rustc_middle::query::Providers;
use rustc_middle::traits;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
@ -84,21 +84,6 @@ macro_rules! type_error_struct {
})
}
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
if typeck_root_def_id != def_id {
return tcx.has_typeck_results(typeck_root_def_id);
}
if let Some(def_id) = def_id.as_local() {
tcx.hir_node_by_def_id(def_id).body_id().is_some()
} else {
false
}
}
fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> {
&tcx.typeck(def_id).used_trait_imports
}
@ -429,11 +414,5 @@ fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! {
pub fn provide(providers: &mut Providers) {
method::provide(providers);
*providers = Providers {
typeck,
diagnostic_only_typeck,
has_typeck_results,
used_trait_imports,
..*providers
};
*providers = Providers { typeck, diagnostic_only_typeck, used_trait_imports, ..*providers };
}

View File

@ -711,13 +711,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.cat_pattern_(place_with_id, subpat, op)?;
}
PatKind::Box(subpat) | PatKind::Ref(subpat, _) | PatKind::Deref(subpat) => {
PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
// box p1, &p1, &mut p1. we can ignore the mutability of
// PatKind::Ref since that information is already contained
// in the type.
let subplace = self.cat_deref(pat, place_with_id)?;
self.cat_pattern_(subplace, subpat, op)?;
}
PatKind::Deref(subpat) => {
let mutable = self.typeck_results.pat_has_ref_mut_binding(subpat);
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
let re_erased = self.tcx().lifetimes.re_erased;
let ty = self.pat_ty_adjusted(subpat)?;
let ty = Ty::new_ref(self.tcx(), re_erased, ty, mutability);
// A deref pattern generates a temporary.
let place = self.cat_rvalue(pat.hir_id, ty);
self.cat_pattern_(place, subpat, op)?;
}
PatKind::Slice(before, ref slice, after) => {
let Some(element_ty) = place_with_id.place.ty().builtin_index() else {

View File

@ -21,7 +21,7 @@ use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::AssocItem;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{GenericArgs, GenericArgsRef};
use rustc_session::lint;
use rustc_span::def_id::DefId;
@ -37,7 +37,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
CandidateStep, MethodAutoderefStepsResult,
};
use rustc_trait_selection::traits::query::CanonicalTyGoal;
use rustc_trait_selection::traits::NormalizeExt;
use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCause};
use std::cell::RefCell;
use std::cmp::max;
@ -99,39 +99,6 @@ impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
#[derive(Debug, Clone)]
pub(crate) struct Candidate<'tcx> {
// Candidates are (I'm not quite sure, but they are mostly) basically
// some metadata on top of a `ty::AssocItem` (without args).
//
// However, method probing wants to be able to evaluate the predicates
// for a function with the args applied - for example, if a function
// has `where Self: Sized`, we don't want to consider it unless `Self`
// is actually `Sized`, and similarly, return-type suggestions want
// to consider the "actual" return type.
//
// The way this is handled is through `xform_self_ty`. It contains
// the receiver type of this candidate, but `xform_self_ty`,
// `xform_ret_ty` and `kind` (which contains the predicates) have the
// generic parameters of this candidate instantiated with the *same set*
// of inference variables, which acts as some weird sort of "query".
//
// When we check out a candidate, we require `xform_self_ty` to be
// a subtype of the passed-in self-type, and this equates the type
// variables in the rest of the fields.
//
// For example, if we have this candidate:
// ```
// trait Foo {
// fn foo(&self) where Self: Sized;
// }
// ```
//
// Then `xform_self_ty` will be `&'erased ?X` and `kind` will contain
// the predicate `?X: Sized`, so if we are evaluating `Foo` for a
// the receiver `&T`, we'll do the subtyping which will make `?X`
// get the right value, then when we evaluate the predicate we'll check
// if `T: Sized`.
xform_self_ty: Ty<'tcx>,
xform_ret_ty: Option<Ty<'tcx>>,
pub(crate) item: ty::AssocItem,
pub(crate) kind: CandidateKind<'tcx>,
pub(crate) import_ids: SmallVec<[LocalDefId; 1]>,
@ -139,17 +106,10 @@ pub(crate) struct Candidate<'tcx> {
#[derive(Debug, Clone)]
pub(crate) enum CandidateKind<'tcx> {
InherentImplCandidate(
GenericArgsRef<'tcx>,
// Normalize obligations
Vec<traits::PredicateObligation<'tcx>>,
),
ObjectCandidate,
TraitCandidate(ty::TraitRef<'tcx>),
WhereClauseCandidate(
// Trait
ty::PolyTraitRef<'tcx>,
),
InherentImplCandidate(DefId),
ObjectCandidate(ty::PolyTraitRef<'tcx>),
TraitCandidate(ty::PolyTraitRef<'tcx>),
WhereClauseCandidate(ty::PolyTraitRef<'tcx>),
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
@ -743,42 +703,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.record_static_candidate(CandidateSource::Impl(impl_def_id));
continue;
}
let (impl_ty, impl_args) = self.impl_ty_and_args(impl_def_id);
let impl_ty = impl_ty.instantiate(self.tcx, impl_args);
debug!("impl_ty: {:?}", impl_ty);
// Determine the receiver type that the method itself expects.
let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, impl_ty, impl_args);
debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty);
// We can't use `FnCtxt::normalize` as it will pollute the
// fcx's fulfillment context after this probe is over.
//
// Note: we only normalize `xform_self_ty` here since the normalization
// of the return type can lead to inference results that prohibit
// valid candidates from being found, see issue #85671
//
// FIXME Postponing the normalization of the return type likely only hides a deeper bug,
// which might be caused by the `param_env` itself. The clauses of the `param_env`
// maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized,
// see issue #89650
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let InferOk { value: xform_self_ty, obligations } =
self.fcx.at(&cause, self.param_env).normalize(xform_self_ty);
debug!(
"assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}",
xform_self_ty, xform_ret_ty
);
self.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
kind: InherentImplCandidate(impl_args, obligations),
kind: InherentImplCandidate(impl_def_id),
import_ids: smallvec![],
},
true,
@ -810,26 +738,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// a `&self` method will wind up with an argument type like `&dyn Trait`.
let trait_ref = principal.with_self_ty(self.tcx, self_ty);
self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
if new_trait_ref.has_non_region_bound_vars() {
this.dcx().span_delayed_bug(
this.span,
"tried to select method from HRTB with non-lifetime bound vars",
);
return;
}
let new_trait_ref = this.instantiate_bound_regions_with_erased(new_trait_ref);
let (xform_self_ty, xform_ret_ty) =
this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args);
this.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
kind: ObjectCandidate,
import_ids: smallvec![],
},
Candidate { item, kind: ObjectCandidate(new_trait_ref), import_ids: smallvec![] },
true,
);
});
@ -860,19 +770,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
});
self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
let trait_ref = this.instantiate_binder_with_fresh_vars(
this.span,
infer::BoundRegionConversionTime::FnCall,
poly_trait_ref,
);
let (xform_self_ty, xform_ret_ty) =
this.xform_self_ty(item, trait_ref.self_ty(), trait_ref.args);
this.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
kind: WhereClauseCandidate(poly_trait_ref),
import_ids: smallvec![],
@ -929,27 +828,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
fn matches_return_type(
&self,
method: ty::AssocItem,
self_ty: Option<Ty<'tcx>>,
expected: Ty<'tcx>,
) -> bool {
fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool {
match method.kind {
ty::AssocKind::Fn => self.probe(|_| {
let args = self.fresh_args_for_item(self.span, method.def_id);
let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args);
let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
if let Some(self_ty) = self_ty {
if self
.at(&ObligationCause::dummy(), self.param_env)
.sup(DefineOpaqueTypes::No, fty.inputs()[0], self_ty)
.is_err()
{
return false;
}
}
self.can_sub(self.param_env, fty.output(), expected)
}),
_ => false,
@ -978,21 +862,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
bound_trait_ref.def_id(),
));
} else {
let new_trait_ref = self.instantiate_binder_with_fresh_vars(
self.span,
infer::BoundRegionConversionTime::FnCall,
bound_trait_ref,
);
let (xform_self_ty, xform_ret_ty) =
self.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args);
self.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
import_ids: import_ids.clone(),
kind: TraitCandidate(new_trait_ref),
kind: TraitCandidate(bound_trait_ref),
},
false,
);
@ -1011,16 +885,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.record_static_candidate(CandidateSource::Trait(trait_def_id));
continue;
}
let (xform_self_ty, xform_ret_ty) =
self.xform_self_ty(item, trait_ref.self_ty(), trait_args);
self.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
import_ids: import_ids.clone(),
kind: TraitCandidate(trait_ref),
kind: TraitCandidate(ty::Binder::dummy(trait_ref)),
},
false,
);
@ -1040,7 +909,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
.filter(|candidate| candidate_filter(&candidate.item))
.filter(|candidate| {
if let Some(return_ty) = self.return_type {
self.matches_return_type(candidate.item, None, return_ty)
self.matches_return_type(candidate.item, return_ty)
} else {
true
}
@ -1450,16 +1319,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> CandidateSource {
match candidate.kind {
InherentImplCandidate(..) => {
InherentImplCandidate(_) => {
CandidateSource::Impl(candidate.item.container_id(self.tcx))
}
ObjectCandidate | WhereClauseCandidate(_) => {
ObjectCandidate(_) | WhereClauseCandidate(_) => {
CandidateSource::Trait(candidate.item.container_id(self.tcx))
}
TraitCandidate(trait_ref) => self.probe(|_| {
let trait_ref =
self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, trait_ref);
let (xform_self_ty, _) =
self.xform_self_ty(candidate.item, trait_ref.self_ty(), trait_ref.args);
let _ = self.at(&ObligationCause::dummy(), self.param_env).sup(
DefineOpaqueTypes::No,
candidate.xform_self_ty,
xform_self_ty,
self_ty,
);
match self.select_trait_candidate(trait_ref) {
@ -1486,54 +1359,46 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
) -> ProbeResult {
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
self.probe(|_| {
// First check that the self type can be related.
let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env).sup(
DefineOpaqueTypes::No,
probe.xform_self_ty,
self_ty,
) {
Ok(InferOk { obligations, value: () }) => obligations,
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
}
};
self.probe(|snapshot| {
let outer_universe = self.universe();
let mut result = ProbeResult::Match;
let mut xform_ret_ty = probe.xform_ret_ty;
debug!(?xform_ret_ty);
let cause = &self.misc(self.span);
let ocx = ObligationCtxt::new(self);
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let mut trait_predicate = None;
let (mut xform_self_ty, mut xform_ret_ty);
let mut parent_pred = None;
// If so, impls may carry other conditions (e.g., where
// clauses) that must be considered. Make sure that those
// match as well (or at least may match, sometimes we
// don't have enough information to fully evaluate).
match probe.kind {
InherentImplCandidate(args, ref ref_obligations) => {
// `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`,
// see the reasons mentioned in the comments in `assemble_inherent_impl_probe`
// for why this is necessary
let InferOk {
value: normalized_xform_ret_ty,
obligations: normalization_obligations,
} = self.fcx.at(&cause, self.param_env).normalize(xform_ret_ty);
xform_ret_ty = normalized_xform_ret_ty;
debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
InherentImplCandidate(impl_def_id) => {
let impl_args = self.fresh_args_for_item(self.span, impl_def_id);
let impl_ty = self.tcx.type_of(impl_def_id).instantiate(self.tcx, impl_args);
(xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, impl_ty, impl_args);
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
// FIXME: Make this `ocx.sup` once we define opaques more eagerly.
match self.at(cause, self.param_env).sup(
DefineOpaqueTypes::No,
xform_self_ty,
self_ty,
) {
Ok(infer_ok) => {
ocx.register_infer_ok_obligations(infer_ok);
}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
}
}
// FIXME: Weirdly, we normalize the ret ty in this candidate, but no other candidates.
xform_ret_ty = ocx.normalize(cause, self.param_env, xform_ret_ty);
// Check whether the impl imposes obligations we have to worry about.
let impl_def_id = probe.item.container_id(self.tcx);
let impl_bounds = self.tcx.predicates_of(impl_def_id);
let impl_bounds = impl_bounds.instantiate(self.tcx, args);
let InferOk { value: impl_bounds, obligations: norm_obligations } =
self.fcx.at(&cause, self.param_env).normalize(impl_bounds);
let impl_bounds =
self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args);
let impl_bounds = ocx.normalize(cause, self.param_env, impl_bounds);
// Convert the bounds into obligations.
let impl_obligations = traits::predicates_for_generics(
ocx.register_obligations(traits::predicates_for_generics(
|idx, span| {
let code = if span.is_dummy() {
traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx)
@ -1549,106 +1414,92 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
},
self.param_env,
impl_bounds,
);
let candidate_obligations = impl_obligations
.chain(norm_obligations)
.chain(ref_obligations.iter().cloned())
.chain(normalization_obligations);
// Evaluate those obligations to see if they might possibly hold.
for o in candidate_obligations {
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
let parent_o = o.clone();
let implied_obligations = traits::elaborate(self.tcx, vec![o]);
for o in implied_obligations {
let parent = if o == parent_o {
None
} else {
if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id())
== self.tcx.lang_items().sized_trait()
{
// We don't care to talk about implicit `Sized` bounds.
continue;
}
Some(parent_o.predicate)
};
if !self.predicate_may_hold(&o) {
possibly_unsatisfied_predicates.push((
o.predicate,
parent,
Some(o.cause),
));
}
}
}
}
));
}
ObjectCandidate | WhereClauseCandidate(..) => {
// These have no additional conditions to check.
}
TraitCandidate(trait_ref) => {
TraitCandidate(poly_trait_ref) => {
// Some trait methods are excluded for arrays before 2021.
// (`array.into_iter()` wants a slice iterator for compatibility.)
if let Some(method_name) = self.method_name {
// Some trait methods are excluded for arrays before 2021.
// (`array.into_iter()` wants a slice iterator for compatibility.)
if self_ty.is_array() && !method_name.span.at_least_rust_2021() {
let trait_def = self.tcx.trait_def(trait_ref.def_id);
let trait_def = self.tcx.trait_def(poly_trait_ref.def_id());
if trait_def.skip_array_during_method_dispatch {
return ProbeResult::NoMatch;
}
}
}
let predicate = ty::Binder::dummy(trait_ref).to_predicate(self.tcx);
parent_pred = Some(predicate);
let obligation =
traits::Obligation::new(self.tcx, cause.clone(), self.param_env, predicate);
if !self.predicate_may_hold(&obligation) {
let trait_ref = self.instantiate_binder_with_fresh_vars(
self.span,
infer::FnCall,
poly_trait_ref,
);
let trait_ref = ocx.normalize(cause, self.param_env, trait_ref);
(xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args);
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
// FIXME: Make this `ocx.sup` once we define opaques more eagerly.
match self.at(cause, self.param_env).sup(
DefineOpaqueTypes::No,
xform_self_ty,
self_ty,
) {
Ok(infer_ok) => {
ocx.register_infer_ok_obligations(infer_ok);
}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
}
}
let obligation = traits::Obligation::new(
self.tcx,
cause.clone(),
self.param_env,
ty::Binder::dummy(trait_ref),
);
// FIXME(-Znext-solver): We only need this hack to deal with fatal
// overflow in the old solver.
if self.infcx.next_trait_solver() || self.infcx.predicate_may_hold(&obligation)
{
ocx.register_obligation(obligation);
} else {
result = ProbeResult::NoMatch;
if self.probe(|_| {
match self.select_trait_candidate(trait_ref) {
Err(_) => return true,
Ok(Some(impl_source))
if !impl_source.borrow_nested_obligations().is_empty() =>
{
for obligation in impl_source.borrow_nested_obligations() {
// Determine exactly which obligation wasn't met, so
// that we can give more context in the error.
if !self.predicate_may_hold(obligation) {
let nested_predicate =
self.resolve_vars_if_possible(obligation.predicate);
let predicate =
self.resolve_vars_if_possible(predicate);
let p = if predicate == nested_predicate {
// Avoid "`MyStruct: Foo` which is required by
// `MyStruct: Foo`" in E0599.
None
} else {
Some(predicate)
};
possibly_unsatisfied_predicates.push((
nested_predicate,
p,
Some(obligation.cause.clone()),
));
}
}
}
_ => {
// Some nested subobligation of this predicate
// failed.
let predicate = self.resolve_vars_if_possible(predicate);
possibly_unsatisfied_predicates.push((predicate, None, None));
if let Ok(Some(candidate)) = self.select_trait_candidate(trait_ref) {
for nested_obligation in candidate.nested_obligations() {
if !self.infcx.predicate_may_hold(&nested_obligation) {
possibly_unsatisfied_predicates.push((
self.resolve_vars_if_possible(nested_obligation.predicate),
Some(self.resolve_vars_if_possible(obligation.predicate)),
Some(nested_obligation.cause),
));
}
}
false
}) {
// This candidate's primary obligation doesn't even
// select - don't bother registering anything in
// `potentially_unsatisfied_predicates`.
}
}
trait_predicate = Some(ty::Binder::dummy(trait_ref).to_predicate(self.tcx));
}
ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => {
let trait_ref = self.instantiate_binder_with_fresh_vars(
self.span,
infer::FnCall,
poly_trait_ref,
);
(xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args);
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
// FIXME: Make this `ocx.sup` once we define opaques more eagerly.
match self.at(cause, self.param_env).sup(
DefineOpaqueTypes::No,
xform_self_ty,
self_ty,
) {
Ok(infer_ok) => {
ocx.register_infer_ok_obligations(infer_ok);
}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
}
}
@ -1656,11 +1507,22 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
// Evaluate those obligations to see if they might possibly hold.
for o in sub_obligations {
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
possibly_unsatisfied_predicates.push((o.predicate, parent_pred, Some(o.cause)));
for error in ocx.select_where_possible() {
result = ProbeResult::NoMatch;
let nested_predicate = self.resolve_vars_if_possible(error.obligation.predicate);
if let Some(trait_predicate) = trait_predicate
&& nested_predicate == self.resolve_vars_if_possible(trait_predicate)
{
// Don't report possibly unsatisfied predicates if the root
// trait obligation from a `TraitCandidate` is unsatisfied.
// That just means the candidate doesn't hold.
} else {
possibly_unsatisfied_predicates.push((
nested_predicate,
Some(self.resolve_vars_if_possible(error.root_obligation.predicate))
.filter(|root_predicate| *root_predicate != nested_predicate),
Some(error.obligation.cause),
));
}
}
@ -1672,36 +1534,37 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// We don't normalize the other candidates for perf/backwards-compat reasons...
// but `self.return_type` is only set on the diagnostic-path, so we
// should be okay doing it here.
if !matches!(probe.kind, InherentImplCandidate(..)) {
let InferOk {
value: normalized_xform_ret_ty,
obligations: normalization_obligations,
} = self.fcx.at(&cause, self.param_env).normalize(xform_ret_ty);
xform_ret_ty = normalized_xform_ret_ty;
debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
// Evaluate those obligations to see if they might possibly hold.
for o in normalization_obligations {
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
possibly_unsatisfied_predicates.push((
o.predicate,
None,
Some(o.cause),
));
}
}
if !matches!(probe.kind, InherentImplCandidate(_)) {
xform_ret_ty = ocx.normalize(&cause, self.param_env, xform_ret_ty);
}
debug!("comparing return_ty {:?} with xform ret ty {:?}", return_ty, xform_ret_ty);
if let ProbeResult::Match = result
&& self
.at(&ObligationCause::dummy(), self.param_env)
.sup(DefineOpaqueTypes::Yes, return_ty, xform_ret_ty)
.is_err()
{
result = ProbeResult::BadReturnType;
match ocx.sup(cause, self.param_env, return_ty, xform_ret_ty) {
Ok(()) => {}
Err(_) => {
result = ProbeResult::BadReturnType;
}
}
// Evaluate those obligations to see if they might possibly hold.
for error in ocx.select_where_possible() {
result = ProbeResult::NoMatch;
possibly_unsatisfied_predicates.push((
error.obligation.predicate,
Some(error.root_obligation.predicate)
.filter(|predicate| *predicate != error.obligation.predicate),
Some(error.root_obligation.cause),
));
}
}
// Previously, method probe used `evaluate_predicate` to determine if a predicate
// was impossible to satisfy. This did a leak check, so we must also do a leak
// check here to prevent backwards-incompatible ambiguity being introduced. See
// `tests/ui/methods/leak-check-disquality.rs` for a simple example of when this
// may happen.
if let Err(_) = self.leak_check(outer_universe, Some(snapshot)) {
result = ProbeResult::NoMatch;
}
result
@ -1894,40 +1757,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn_sig.instantiate(self.tcx, args)
};
self.instantiate_bound_regions_with_erased(xform_fn_sig)
}
/// Gets the type of an impl and generate generic parameters with inference vars.
fn impl_ty_and_args(
&self,
impl_def_id: DefId,
) -> (ty::EarlyBinder<Ty<'tcx>>, GenericArgsRef<'tcx>) {
(self.tcx.type_of(impl_def_id), self.fresh_args_for_item(self.span, impl_def_id))
}
/// Replaces late-bound-regions bound by `value` with `'static` using
/// `ty::instantiate_bound_regions_with_erased`.
///
/// This is only a reasonable thing to do during the *probe* phase, not the *confirm* phase, of
/// method matching. It is reasonable during the probe phase because we don't consider region
/// relationships at all. Therefore, we can just replace all the region variables with 'static
/// rather than creating fresh region variables. This is nice for two reasons:
///
/// 1. Because the numbers of the region variables would otherwise be fairly unique to this
/// particular method call, it winds up creating fewer types overall, which helps for memory
/// usage. (Admittedly, this is a rather small effect, though measurable.)
///
/// 2. It makes it easier to deal with higher-ranked trait bounds, because we can replace any
/// late-bound regions with 'static. Otherwise, if we were going to replace late-bound
/// regions with actual region variables as is proper, we'd have to ensure that the same
/// region got replaced with the same variable, which requires a bit more coordination
/// and/or tracking the instantiations and
/// so forth.
fn instantiate_bound_regions_with_erased<T>(&self, value: ty::Binder<'tcx, T>) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
self.tcx.instantiate_bound_regions_with_erased(value)
self.tcx.instantiate_bound_regions_with_erased(xform_fn_sig)
}
/// Determine if the given associated item type is relevant in the current context.
@ -2051,10 +1881,10 @@ impl<'tcx> Candidate<'tcx> {
Pick {
item: self.item,
kind: match self.kind {
InherentImplCandidate(..) => InherentImplPick,
ObjectCandidate => ObjectPick,
InherentImplCandidate(_) => InherentImplPick,
ObjectCandidate(_) => ObjectPick,
TraitCandidate(_) => TraitPick,
WhereClauseCandidate(ref trait_ref) => {
WhereClauseCandidate(trait_ref) => {
// Only trait derived from where-clauses should
// appear here, so they should not contain any
// inference variables or other artifacts. This
@ -2065,7 +1895,7 @@ impl<'tcx> Candidate<'tcx> {
&& !trait_ref.skip_binder().args.has_placeholders()
);
WhereClausePick(*trait_ref)
WhereClausePick(trait_ref)
}
},
import_ids: self.import_ids.clone(),

View File

@ -3291,14 +3291,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param.name.ident(),
));
let bounds_span = hir_generics.bounds_span_for_suggestions(def_id);
if rcvr_ty.is_ref() && param.is_impl_trait() && bounds_span.is_some() {
if rcvr_ty.is_ref()
&& param.is_impl_trait()
&& let Some((bounds_span, _)) = bounds_span
{
err.multipart_suggestions(
msg,
candidates.iter().map(|t| {
vec![
(param.span.shrink_to_lo(), "(".to_string()),
(
bounds_span.unwrap(),
bounds_span,
format!(" + {})", self.tcx.def_path_str(t.def_id)),
),
]
@ -3308,32 +3311,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
let (sp, introducer) = if let Some(span) = bounds_span {
(span, Introducer::Plus)
} else if let Some(colon_span) = param.colon_span {
(colon_span.shrink_to_hi(), Introducer::Nothing)
} else if param.is_impl_trait() {
(param.span.shrink_to_hi(), Introducer::Plus)
} else {
(param.span.shrink_to_hi(), Introducer::Colon)
};
let (sp, introducer, open_paren_sp) =
if let Some((span, open_paren_sp)) = bounds_span {
(span, Introducer::Plus, open_paren_sp)
} else if let Some(colon_span) = param.colon_span {
(colon_span.shrink_to_hi(), Introducer::Nothing, None)
} else if param.is_impl_trait() {
(param.span.shrink_to_hi(), Introducer::Plus, None)
} else {
(param.span.shrink_to_hi(), Introducer::Colon, None)
};
err.span_suggestions(
sp,
let all_suggs = candidates.iter().map(|cand| {
let suggestion = format!(
"{} {}",
match introducer {
Introducer::Plus => " +",
Introducer::Colon => ":",
Introducer::Nothing => "",
},
self.tcx.def_path_str(cand.def_id)
);
let mut suggs = vec![];
if let Some(open_paren_sp) = open_paren_sp {
suggs.push((open_paren_sp, "(".to_string()));
suggs.push((sp, format!("){suggestion}")));
} else {
suggs.push((sp, suggestion));
}
suggs
});
err.multipart_suggestions(
msg,
candidates.iter().map(|t| {
format!(
"{} {}",
match introducer {
Introducer::Plus => " +",
Introducer::Colon => ":",
Introducer::Nothing => "",
},
self.tcx.def_path_str(t.def_id)
)
}),
all_suggs,
Applicability::MaybeIncorrect,
);
return;
}
Node::Item(hir::Item {

View File

@ -551,15 +551,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fn visit_coroutine_interior(&mut self) {
let fcx_typeck_results = self.fcx.typeck_results.borrow();
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
self.tcx().with_stable_hashing_context(move |ref hcx| {
for (&expr_def_id, predicates) in
fcx_typeck_results.coroutine_interior_predicates.to_sorted(hcx, false).into_iter()
{
let predicates =
self.resolve(predicates.clone(), &self.fcx.tcx.def_span(expr_def_id));
self.typeck_results.coroutine_interior_predicates.insert(expr_def_id, predicates);
}
})
for (predicate, cause) in &fcx_typeck_results.coroutine_stalled_predicates {
let (predicate, cause) = self.resolve((*predicate, cause.clone()), &cause.span);
self.typeck_results.coroutine_stalled_predicates.insert((predicate, cause));
}
}
#[instrument(skip(self), level = "debug")]

View File

@ -239,7 +239,7 @@ impl Subdiagnostic for RegionOriginNote<'_> {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
let mut label_or_note = |span, msg: DiagMessage| {
let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
@ -304,7 +304,7 @@ impl Subdiagnostic for LifetimeMismatchLabels {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
match self {
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
@ -352,7 +352,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
let mut mk_suggestion = || {
let (
@ -454,7 +454,7 @@ impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
mut self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
self.unmet_requirements
.push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
@ -773,7 +773,7 @@ impl Subdiagnostic for ConsiderBorrowingParamHelp {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: F,
f: &F,
) {
let mut type_param_span: MultiSpan = self.spans.clone().into();
for &span in &self.spans {
@ -818,7 +818,7 @@ impl Subdiagnostic for DynTraitConstraintSuggestion {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: F,
f: &F,
) {
let mut multi_span: MultiSpan = vec![self.span].into();
multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label);
@ -865,7 +865,7 @@ impl Subdiagnostic for ReqIntroducedLocations {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
mut self,
diag: &mut Diag<'_, G>,
f: F,
f: &F,
) {
for sp in self.spans {
self.span.push_span_label(sp, fluent::infer_ril_introduced_here);
@ -888,7 +888,7 @@ impl Subdiagnostic for MoreTargeted {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
diag.code(E0772);
diag.primary_message(fluent::infer_more_targeted);
@ -1293,7 +1293,7 @@ impl Subdiagnostic for SuggestTuplePatternMany {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: F,
f: &F,
) {
diag.arg("path", self.path);
let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into());

View File

@ -163,7 +163,7 @@ impl Subdiagnostic for RegionExplanation<'_> {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: F,
f: &F,
) {
diag.arg("pref_kind", self.prefix);
diag.arg("suff_kind", self.suffix);

View File

@ -2369,7 +2369,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
generic_param_scope = self.tcx.local_parent(generic_param_scope);
}
// type_param_sugg_span is (span, has_bounds)
// type_param_sugg_span is (span, has_bounds, needs_parentheses)
let (type_scope, type_param_sugg_span) = match bound_kind {
GenericKind::Param(param) => {
let generics = self.tcx.generics_of(generic_param_scope);
@ -2380,10 +2380,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// instead we suggest `T: 'a + 'b` in that case.
let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
Some(span) => Some((span, true)),
Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)),
// If `param` corresponds to `Self`, no usable suggestion span.
None if generics.has_self && param.index == 0 => None,
None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false)),
None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false, None)),
};
(scope, sugg_span)
}
@ -2406,12 +2406,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut suggs = vec![];
let lt_name = self.suggest_name_region(sub, &mut suggs);
if let Some((sp, has_lifetimes)) = type_param_sugg_span
if let Some((sp, has_lifetimes, open_paren_sp)) = type_param_sugg_span
&& suggestion_scope == type_scope
{
let suggestion =
if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
suggs.push((sp, suggestion))
if let Some(open_paren_sp) = open_paren_sp {
suggs.push((open_paren_sp, "(".to_string()));
suggs.push((sp, format!("){suggestion}")));
} else {
suggs.push((sp, suggestion))
}
} else if let GenericKind::Alias(ref p) = bound_kind
&& let ty::Projection = p.kind(self.tcx)
&& let DefKind::AssocTy = self.tcx.def_kind(p.def_id)

View File

@ -759,7 +759,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
tcx.hir().par_body_owners(|def_id| {
if tcx.is_coroutine(def_id.to_def_id()) {
tcx.ensure().mir_coroutine_witnesses(def_id);
tcx.ensure().check_coroutine_obligations(def_id);
tcx.ensure().check_coroutine_obligations(
tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(),
);
}
});
sess.time("layout_testing", || layout_test::test_layout(tcx));

View File

@ -8,7 +8,7 @@ use rustc_codegen_ssa::CodegenResults;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, OnceLock, WorkerLocal};
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
use rustc_hir::def_id::{StableCrateId, StableCrateIdMap, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
use rustc_incremental::setup_dep_graph;
use rustc_metadata::creader::CStore;
@ -140,11 +140,16 @@ impl<'tcx> Queries<'tcx> {
let cstore = FreezeLock::new(Box::new(CStore::new(
self.compiler.codegen_backend.metadata_loader(),
stable_crate_id,
)) as _);
let definitions = FreezeLock::new(Definitions::new(stable_crate_id));
let untracked =
Untracked { cstore, source_span: AppendOnlyIndexVec::new(), definitions };
let stable_crate_ids = FreezeLock::new(StableCrateIdMap::default());
let untracked = Untracked {
cstore,
source_span: AppendOnlyIndexVec::new(),
definitions,
stable_crate_ids,
};
let qcx = passes::create_global_ctxt(
self.compiler,
@ -158,7 +163,8 @@ impl<'tcx> Queries<'tcx> {
);
qcx.enter(|tcx| {
let feed = tcx.feed_local_crate();
let feed = tcx.create_crate_num(stable_crate_id).unwrap();
assert_eq!(feed.key(), LOCAL_CRATE);
feed.crate_name(crate_name);
let feed = tcx.feed_unit_query();

View File

@ -321,6 +321,7 @@ fn test_search_paths_tracking_hash_different_order() {
&opts.target_triple,
&early_dcx,
search_path,
false,
));
};

View File

@ -1769,13 +1769,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
}
declare_lint! {
/// The `keyword_idents` lint detects edition keywords being used as an
/// The `keyword_idents_2018` lint detects edition keywords being used as an
/// identifier.
///
/// ### Example
///
/// ```rust,edition2015,compile_fail
/// #![deny(keyword_idents)]
/// #![deny(keyword_idents_2018)]
/// // edition 2015
/// fn dyn() {}
/// ```
@ -1804,7 +1804,7 @@ declare_lint! {
/// [editions]: https://doc.rust-lang.org/edition-guide/
/// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
/// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
pub KEYWORD_IDENTS,
pub KEYWORD_IDENTS_2018,
Allow,
"detects edition keywords being used as an identifier",
@future_incompatible = FutureIncompatibleInfo {
@ -1813,9 +1813,54 @@ declare_lint! {
};
}
declare_lint! {
/// The `keyword_idents_2024` lint detects edition keywords being used as an
/// identifier.
///
/// ### Example
///
/// ```rust,edition2015,compile_fail
/// #![deny(keyword_idents_2024)]
/// // edition 2015
/// fn gen() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Rust [editions] allow the language to evolve without breaking
/// backwards compatibility. This lint catches code that uses new keywords
/// that are added to the language that are used as identifiers (such as a
/// variable name, function name, etc.). If you switch the compiler to a
/// new edition without updating the code, then it will fail to compile if
/// you are using a new keyword as an identifier.
///
/// You can manually change the identifiers to a non-keyword, or use a
/// [raw identifier], for example `r#gen`, to transition to a new edition.
///
/// This lint solves the problem automatically. It is "allow" by default
/// because the code is perfectly valid in older editions. The [`cargo
/// fix`] tool with the `--edition` flag will switch this lint to "warn"
/// and automatically apply the suggested fix from the compiler (which is
/// to use a raw identifier). This provides a completely automated way to
/// update old code for a new edition.
///
/// [editions]: https://doc.rust-lang.org/edition-guide/
/// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
/// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
pub KEYWORD_IDENTS_2024,
Allow,
"detects edition keywords being used as an identifier",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
};
}
declare_lint_pass!(
/// Check for uses of edition keywords used as an identifier.
KeywordIdents => [KEYWORD_IDENTS]
KeywordIdents => [KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024]
);
struct UnderMacro(bool);
@ -1841,42 +1886,39 @@ impl KeywordIdents {
UnderMacro(under_macro): UnderMacro,
ident: Ident,
) {
let next_edition = match cx.sess().edition() {
Edition::Edition2015 => {
match ident.name {
kw::Async | kw::Await | kw::Try => Edition::Edition2018,
let (lint, edition) = match ident.name {
kw::Async | kw::Await | kw::Try => (KEYWORD_IDENTS_2018, Edition::Edition2018),
// rust-lang/rust#56327: Conservatively do not
// attempt to report occurrences of `dyn` within
// macro definitions or invocations, because `dyn`
// can legitimately occur as a contextual keyword
// in 2015 code denoting its 2018 meaning, and we
// do not want rustfix to inject bugs into working
// code by rewriting such occurrences.
//
// But if we see `dyn` outside of a macro, we know
// its precise role in the parsed AST and thus are
// assured this is truly an attempt to use it as
// an identifier.
kw::Dyn if !under_macro => Edition::Edition2018,
// rust-lang/rust#56327: Conservatively do not
// attempt to report occurrences of `dyn` within
// macro definitions or invocations, because `dyn`
// can legitimately occur as a contextual keyword
// in 2015 code denoting its 2018 meaning, and we
// do not want rustfix to inject bugs into working
// code by rewriting such occurrences.
//
// But if we see `dyn` outside of a macro, we know
// its precise role in the parsed AST and thus are
// assured this is truly an attempt to use it as
// an identifier.
kw::Dyn if !under_macro => (KEYWORD_IDENTS_2018, Edition::Edition2018),
_ => return,
}
}
kw::Gen => (KEYWORD_IDENTS_2024, Edition::Edition2024),
// There are no new keywords yet for the 2018 edition and beyond.
_ => return,
};
// Don't lint `r#foo`.
if cx.sess().psess.raw_identifier_spans.contains(ident.span) {
if ident.span.edition() >= edition
|| cx.sess().psess.raw_identifier_spans.contains(ident.span)
{
return;
}
cx.emit_span_lint(
KEYWORD_IDENTS,
lint,
ident.span,
BuiltinKeywordIdents { kw: ident, next: next_edition, suggestion: ident.span },
BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span },
);
}
}

View File

@ -741,7 +741,7 @@ impl<'tcx> LateContext<'tcx> {
.filter(|typeck_results| typeck_results.hir_owner == id.owner)
.or_else(|| {
self.tcx
.has_typeck_results(id.owner.to_def_id())
.has_typeck_results(id.owner.def_id)
.then(|| self.tcx.typeck(id.owner.def_id))
})
.and_then(|typeck_results| typeck_results.type_dependent_def(id))

View File

@ -2,7 +2,7 @@
#![allow(rustc::untranslatable_diagnostic)]
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
use rustc_errors::{add_elided_lifetime_in_path_suggestion, Diag};
use rustc_errors::{elided_lifetime_in_path_suggestion, Diag};
use rustc_errors::{Applicability, SuggestionStyle};
use rustc_middle::middle::stability;
use rustc_session::lint::BuiltinLintDiag;
@ -74,13 +74,15 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
diag.span_note(span_def, "the macro is defined here");
}
BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => {
add_elided_lifetime_in_path_suggestion(
sess.source_map(),
diag,
n,
path_span,
incl_angl_brckt,
insertion_span,
diag.subdiagnostic(
sess.dcx(),
elided_lifetime_in_path_suggestion(
sess.source_map(),
n,
path_span,
incl_angl_brckt,
insertion_span,
),
);
}
BuiltinLintDiag::UnknownCrateTypes(span, note, sugg) => {

View File

@ -27,7 +27,7 @@ impl Subdiagnostic for OverruledAttributeSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
match self {
OverruledAttributeSub::DefaultSource { id } => {

View File

@ -312,6 +312,8 @@ fn register_builtins(store: &mut LintStore) {
// MACRO_USE_EXTERN_CRATE
);
add_lint_group!("keyword_idents", KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024);
add_lint_group!(
"refining_impl_trait",
REFINING_IMPL_TRAIT_REACHABLE,
@ -324,7 +326,7 @@ fn register_builtins(store: &mut LintStore) {
store.register_renamed("bare_trait_object", "bare_trait_objects");
store.register_renamed("unstable_name_collision", "unstable_name_collisions");
store.register_renamed("unused_doc_comment", "unused_doc_comments");
store.register_renamed("async_idents", "keyword_idents");
store.register_renamed("async_idents", "keyword_idents_2018");
store.register_renamed("exceeding_bitshifts", "arithmetic_overflow");
store.register_renamed("redundant_semicolon", "redundant_semicolons");
store.register_renamed("overlapping_patterns", "overlapping_range_endpoints");

View File

@ -274,7 +274,7 @@ impl<'a, 'b> Subdiagnostic for SuggestChangingAssocTypes<'a, 'b> {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
// Access to associates types should use `<T as Bound>::Assoc`, which does not need a
// bound. Let's see if this type does that.
@ -330,7 +330,7 @@ impl Subdiagnostic for BuiltinTypeAliasGenericBoundsSuggestion {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
diag.multipart_suggestion(
fluent::lint_suggestion,
@ -451,7 +451,7 @@ impl Subdiagnostic for BuiltinUnpermittedTypeInitSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
let mut err = self.err;
loop {
@ -506,7 +506,7 @@ impl Subdiagnostic for BuiltinClashingExternSub<'_> {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
let mut expected_str = DiagStyledString::new();
expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false);
@ -788,7 +788,7 @@ impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
for (c, span) in self.spans {
diag.span_label(span, format!("{c:?}"));
@ -806,7 +806,7 @@ impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
match self {
HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
@ -954,7 +954,7 @@ impl Subdiagnostic for NonBindingLetSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar;
@ -1240,7 +1240,7 @@ impl Subdiagnostic for NonSnakeCaseDiagSub {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
match self {
NonSnakeCaseDiagSub::Label { span } => {
@ -1482,7 +1482,7 @@ impl Subdiagnostic for OverflowingBinHexSign {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: F,
_f: &F,
) {
match self {
OverflowingBinHexSign::Positive => {

View File

@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
|| Some(def_id) == cx.tcx.lang_items().panic_fn()
|| f_diagnostic_name == Some(sym::panic_str)
|| f_diagnostic_name == Some(sym::panic_str_2015)
{
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
if matches!(

View File

@ -71,6 +71,7 @@ impl SubdiagnosticDerive {
span_field: None,
applicability: None,
has_suggestion_parts: false,
has_subdiagnostic: false,
is_enum,
};
builder.into_tokens().unwrap_or_else(|v| v.to_compile_error())
@ -90,7 +91,7 @@ impl SubdiagnosticDerive {
fn add_to_diag_with<__G, __F>(
self,
#diag: &mut rustc_errors::Diag<'_, __G>,
#f: __F
#f: &__F
) where
__G: rustc_errors::EmissionGuarantee,
__F: rustc_errors::SubdiagMessageOp<__G>,
@ -133,6 +134,10 @@ struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
/// during finalization if still `false`.
has_suggestion_parts: bool,
/// Set to true when a `#[subdiagnostic]` field is encountered, used to suppress the error
/// emitted when no subdiagnostic kinds are specified on the variant itself.
has_subdiagnostic: bool,
/// Set to true when this variant is an enum variant rather than just the body of a struct.
is_enum: bool,
}
@ -373,6 +378,13 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
Ok(quote! {})
}
"subdiagnostic" => {
let f = &self.parent.f;
let diag = &self.parent.diag;
let binding = &info.binding;
self.has_subdiagnostic = true;
Ok(quote! { #binding.add_to_diag_with(#diag, #f); })
}
_ => {
let mut span_attrs = vec![];
if kind_stats.has_multipart_suggestion {
@ -480,18 +492,6 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
let kind_slugs = self.identify_kind()?;
if kind_slugs.is_empty() {
if self.is_enum {
// It's okay for a variant to not be a subdiagnostic at all..
return Ok(quote! {});
} else {
// ..but structs should always be _something_.
throw_span_err!(
self.variant.ast().ident.span().unwrap(),
"subdiagnostic kind not specified"
);
}
};
let kind_stats: KindsStatistics =
kind_slugs.iter().map(|(kind, _slug, _no_span)| kind).collect();
@ -510,6 +510,19 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
.map(|binding| self.generate_field_attr_code(binding, kind_stats))
.collect();
if kind_slugs.is_empty() {
if self.is_enum {
// It's okay for a variant to not be a subdiagnostic at all..
return Ok(quote! {});
} else if !self.has_subdiagnostic {
// ..but structs should always be _something_.
throw_span_err!(
self.variant.ast().ident.span().unwrap(),
"subdiagnostic kind not specified"
);
}
};
let span_field = self.span_field.value_ref();
let diag = &self.parent.diag;

View File

@ -144,6 +144,7 @@ decl_derive!(
help,
note,
warning,
subdiagnostic,
suggestion,
suggestion_short,
suggestion_hidden,

View File

@ -13,10 +13,10 @@ use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard};
use rustc_errors::DiagCtxt;
use rustc_expand::base::SyntaxExtension;
use rustc_fs_util::try_canonicalize;
use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE};
use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
use rustc_index::IndexVec;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
use rustc_session::config::{self, CrateType, ExternLocation};
use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
use rustc_session::lint;
@ -62,9 +62,6 @@ pub struct CStore {
/// This crate has a `#[alloc_error_handler]` item.
has_alloc_error_handler: bool,
/// The interned [StableCrateId]s.
pub(crate) stable_crate_ids: StableCrateIdMap,
/// Unused externs of the crate
unused_externs: Vec<Symbol>,
}
@ -165,25 +162,27 @@ impl CStore {
})
}
fn intern_stable_crate_id(&mut self, root: &CrateRoot) -> Result<CrateNum, CrateError> {
assert_eq!(self.metas.len(), self.stable_crate_ids.len());
let num = CrateNum::new(self.stable_crate_ids.len());
if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) {
fn intern_stable_crate_id<'tcx>(
&mut self,
root: &CrateRoot,
tcx: TyCtxt<'tcx>,
) -> Result<TyCtxtFeed<'tcx, CrateNum>, CrateError> {
assert_eq!(self.metas.len(), tcx.untracked().stable_crate_ids.read().len());
let num = tcx.create_crate_num(root.stable_crate_id()).map_err(|existing| {
// Check for (potential) conflicts with the local crate
if existing == LOCAL_CRATE {
Err(CrateError::SymbolConflictsCurrent(root.name()))
CrateError::SymbolConflictsCurrent(root.name())
} else if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name())
{
let crate_name0 = root.name();
Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1))
CrateError::StableCrateIdCollision(crate_name0, crate_name1)
} else {
Err(CrateError::NotFound(root.name()))
CrateError::NotFound(root.name())
}
} else {
self.metas.push(None);
self.stable_crate_ids.insert(root.stable_crate_id(), num);
Ok(num)
}
})?;
self.metas.push(None);
Ok(num)
}
pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
@ -289,12 +288,7 @@ impl CStore {
}
}
pub fn new(
metadata_loader: Box<MetadataLoaderDyn>,
local_stable_crate_id: StableCrateId,
) -> CStore {
let mut stable_crate_ids = StableCrateIdMap::default();
stable_crate_ids.insert(local_stable_crate_id, LOCAL_CRATE);
pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
CStore {
metadata_loader,
// We add an empty entry for LOCAL_CRATE (which maps to zero) in
@ -307,7 +301,6 @@ impl CStore {
alloc_error_handler_kind: None,
has_global_allocator: false,
has_alloc_error_handler: false,
stable_crate_ids,
unused_externs: Vec::new(),
}
}
@ -416,7 +409,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
let private_dep = self.is_private_dep(name.as_str(), private_dep);
// Claim this crate number and cache it
let cnum = self.cstore.intern_stable_crate_id(&crate_root)?;
let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?;
let cnum = feed.key();
info!(
"register crate `{}` (cnum = {}. private_dep = {})",

View File

@ -1208,7 +1208,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
tcx.arena.alloc_from_iter(self.root.stability_implications.decode(self))
}
/// Iterates over the language items in the given crate.
/// Iterates over the lang items in the given crate.
fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, LangItem)] {
tcx.arena.alloc_from_iter(
self.root

View File

@ -629,13 +629,6 @@ impl CrateStore for CStore {
self.get_crate_data(cnum).root.stable_crate_id
}
fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum {
*self
.stable_crate_ids
.get(&stable_crate_id)
.unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}"))
}
/// Returns the `DefKey` for a given `DefId`. This indicates the
/// parent `DefId` as well as some idea of what kind of data the
/// `DefId` refers to.
@ -657,7 +650,13 @@ fn provide_cstore_hooks(providers: &mut Providers) {
// If this is a DefPathHash from an upstream crate, let the CrateStore map
// it to a DefId.
let cstore = CStore::from_tcx(tcx.tcx);
let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id);
let cnum = *tcx
.untracked()
.stable_crate_ids
.read()
.get(&stable_crate_id)
.unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}"));
assert_ne!(cnum, LOCAL_CRATE);
let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash);
DefId { krate: cnum, index: def_index }
};

View File

@ -1,4 +1,4 @@
//! Detecting language items.
//! Detecting lang items.
//!
//! Language items are items that represent concepts intrinsic to the language
//! itself. Examples are:

View File

@ -238,6 +238,20 @@ impl<'tcx> Const<'tcx> {
}
}
/// Determines whether we need to add this const to `required_consts`. This is the case if and
/// only if evaluating it may error.
#[inline]
pub fn is_required_const(&self) -> bool {
match self {
Const::Ty(c) => match c.kind() {
ty::ConstKind::Value(_) => false, // already a value, cannot error
_ => true,
},
Const::Val(..) => false, // already a value, cannot error
Const::Unevaluated(..) => true,
}
}
#[inline]
pub fn try_to_scalar(self) -> Option<Scalar> {
match self {

View File

@ -2,7 +2,7 @@ use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar};
use crate::error;
use crate::mir::{ConstAlloc, ConstValue};
use crate::ty::{layout, tls, Ty, TyCtxt, ValTree};
use crate::ty::{self, layout, tls, Ty, TyCtxt, ValTree};
use rustc_ast_ir::Mutability;
use rustc_data_structures::sync::Lock;
@ -344,6 +344,11 @@ pub enum UndefinedBehaviorInfo<'tcx> {
InvalidFunctionPointer(Pointer<AllocId>),
/// Using a pointer-not-to-a-vtable as vtable pointer.
InvalidVTablePointer(Pointer<AllocId>),
/// Using a vtable for the wrong trait.
InvalidVTableTrait {
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
},
/// Using a string that is not valid UTF-8,
InvalidStr(std::str::Utf8Error),
/// Using uninitialized data where it is not allowed.
@ -414,34 +419,86 @@ impl From<PointerKind> for ExpectedKind {
#[derive(Debug)]
pub enum ValidationErrorKind<'tcx> {
PointerAsInt { expected: ExpectedKind },
PointerAsInt {
expected: ExpectedKind,
},
PartialPointer,
PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> },
PtrToStatic { ptr_kind: PointerKind },
PtrToUninhabited {
ptr_kind: PointerKind,
ty: Ty<'tcx>,
},
PtrToStatic {
ptr_kind: PointerKind,
},
ConstRefToMutable,
ConstRefToExtern,
MutableRefToImmutable,
UnsafeCellInImmutable,
NullFnPtr,
NeverVal,
NullablePtrOutOfRange { range: WrappingRange, max_value: u128 },
PtrOutOfRange { range: WrappingRange, max_value: u128 },
OutOfRange { value: String, range: WrappingRange, max_value: u128 },
UninhabitedVal { ty: Ty<'tcx> },
InvalidEnumTag { value: String },
NullablePtrOutOfRange {
range: WrappingRange,
max_value: u128,
},
PtrOutOfRange {
range: WrappingRange,
max_value: u128,
},
OutOfRange {
value: String,
range: WrappingRange,
max_value: u128,
},
UninhabitedVal {
ty: Ty<'tcx>,
},
InvalidEnumTag {
value: String,
},
UninhabitedEnumVariant,
Uninit { expected: ExpectedKind },
InvalidVTablePtr { value: String },
InvalidMetaSliceTooLarge { ptr_kind: PointerKind },
InvalidMetaTooLarge { ptr_kind: PointerKind },
UnalignedPtr { ptr_kind: PointerKind, required_bytes: u64, found_bytes: u64 },
NullPtr { ptr_kind: PointerKind },
DanglingPtrNoProvenance { ptr_kind: PointerKind, pointer: String },
DanglingPtrOutOfBounds { ptr_kind: PointerKind },
DanglingPtrUseAfterFree { ptr_kind: PointerKind },
InvalidBool { value: String },
InvalidChar { value: String },
InvalidFnPtr { value: String },
Uninit {
expected: ExpectedKind,
},
InvalidVTablePtr {
value: String,
},
InvalidMetaWrongTrait {
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
},
InvalidMetaSliceTooLarge {
ptr_kind: PointerKind,
},
InvalidMetaTooLarge {
ptr_kind: PointerKind,
},
UnalignedPtr {
ptr_kind: PointerKind,
required_bytes: u64,
found_bytes: u64,
},
NullPtr {
ptr_kind: PointerKind,
},
DanglingPtrNoProvenance {
ptr_kind: PointerKind,
pointer: String,
},
DanglingPtrOutOfBounds {
ptr_kind: PointerKind,
},
DanglingPtrUseAfterFree {
ptr_kind: PointerKind,
},
InvalidBool {
value: String,
},
InvalidChar {
value: String,
},
InvalidFnPtr {
value: String,
},
}
/// Error information for when the program did something that might (or might not) be correct

View File

@ -985,7 +985,8 @@ impl<'tcx> Debug for Rvalue<'tcx> {
Ref(region, borrow_kind, ref place) => {
let kind_str = match borrow_kind {
BorrowKind::Shared => "",
BorrowKind::Fake => "fake ",
BorrowKind::Fake(FakeBorrowKind::Deep) => "fake ",
BorrowKind::Fake(FakeBorrowKind::Shallow) => "fake shallow ",
BorrowKind::Mut { .. } => "mut ",
};

View File

@ -236,6 +236,11 @@ impl<'tcx> PlaceRef<'tcx> {
}
}
#[inline]
pub fn to_place(&self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
Place { local: self.local, projection: tcx.mk_place_elems(self.projection) }
}
#[inline]
pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
if let &[ref proj_base @ .., elem] = self.projection {
@ -446,7 +451,7 @@ impl<'tcx> Rvalue<'tcx> {
impl BorrowKind {
pub fn mutability(&self) -> Mutability {
match *self {
BorrowKind::Shared | BorrowKind::Fake => Mutability::Not,
BorrowKind::Shared | BorrowKind::Fake(_) => Mutability::Not,
BorrowKind::Mut { .. } => Mutability::Mut,
}
}
@ -454,7 +459,7 @@ impl BorrowKind {
pub fn allows_two_phase_borrow(&self) -> bool {
match *self {
BorrowKind::Shared
| BorrowKind::Fake
| BorrowKind::Fake(_)
| BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
false
}

View File

@ -165,13 +165,16 @@ pub enum BorrowKind {
/// Data must be immutable and is aliasable.
Shared,
/// The immediately borrowed place must be immutable, but projections from
/// it don't need to be. For example, a shallow borrow of `a.b` doesn't
/// conflict with a mutable borrow of `a.b.c`.
/// An immutable, aliasable borrow that is discarded after borrow-checking. Can behave either
/// like a normal shared borrow or like a special shallow borrow (see [`FakeBorrowKind`]).
///
/// This is used when lowering matches: when matching on a place we want to
/// ensure that place have the same value from the start of the match until
/// an arm is selected. This prevents this code from compiling:
/// This is used when lowering index expressions and matches. This is used to prevent code like
/// the following from compiling:
/// ```compile_fail,E0510
/// let mut x: &[_] = &[[0, 1]];
/// let y: &[_] = &[];
/// let _ = x[0][{x = y; 1}];
/// ```
/// ```compile_fail,E0510
/// let mut x = &Some(0);
/// match *x {
@ -180,11 +183,8 @@ pub enum BorrowKind {
/// Some(_) => (),
/// }
/// ```
/// This can't be a shared borrow because mutably borrowing (*x as Some).0
/// should not prevent `if let None = x { ... }`, for example, because the
/// mutating `(*x as Some).0` can't affect the discriminant of `x`.
/// We can also report errors with this kind of borrow differently.
Fake,
Fake(FakeBorrowKind),
/// Data is mutable and not aliasable.
Mut { kind: MutBorrowKind },
@ -240,6 +240,57 @@ pub enum MutBorrowKind {
ClosureCapture,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(Hash, HashStable)]
pub enum FakeBorrowKind {
/// A shared shallow borrow. The immediately borrowed place must be immutable, but projections
/// from it don't need to be. For example, a shallow borrow of `a.b` doesn't conflict with a
/// mutable borrow of `a.b.c`.
///
/// This is used when lowering matches: when matching on a place we want to ensure that place
/// have the same value from the start of the match until an arm is selected. This prevents this
/// code from compiling:
/// ```compile_fail,E0510
/// let mut x = &Some(0);
/// match *x {
/// None => (),
/// Some(_) if { x = &None; false } => (),
/// Some(_) => (),
/// }
/// ```
/// This can't be a shared borrow because mutably borrowing `(*x as Some).0` should not checking
/// the discriminant or accessing other variants, because the mutating `(*x as Some).0` can't
/// affect the discriminant of `x`. E.g. the following is allowed:
/// ```rust
/// let mut x = Some(0);
/// match x {
/// Some(_)
/// if {
/// if let Some(ref mut y) = x {
/// *y += 1;
/// };
/// true
/// } => {}
/// _ => {}
/// }
/// ```
Shallow,
/// A shared (deep) borrow. Data must be immutable and is aliasable.
///
/// This is used when lowering deref patterns, where shallow borrows wouldn't prevent something
/// like:
// ```compile_fail
// let mut b = Box::new(false);
// match b {
// deref!(true) => {} // not reached because `*b == false`
// _ if { *b = true; false } => {} // not reached because the guard is `false`
// deref!(false) => {} // not reached because the guard changed it
// // UB because we reached the unreachable.
// }
// ```
Deep,
}
///////////////////////////////////////////////////////////////////////////
// Statements

View File

@ -294,7 +294,7 @@ impl BorrowKind {
// We have no type corresponding to a shallow borrow, so use
// `&` as an approximation.
BorrowKind::Fake => hir::Mutability::Not,
BorrowKind::Fake(_) => hir::Mutability::Not,
}
}
}

Some files were not shown because too many files have changed in this diff Show More