Merge from rustc
This commit is contained in:
commit
5cf7dd0bbf
421 changed files with 5317 additions and 3487 deletions
153
Cargo.lock
153
Cargo.lock
|
|
@ -43,7 +43,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
"zerocopy 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -567,7 +567,7 @@ dependencies = [
|
|||
"termize",
|
||||
"tokio",
|
||||
"toml 0.7.8",
|
||||
"ui_test",
|
||||
"ui_test 0.26.5",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
|
|
@ -1442,7 +1442,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.13.3+wasi-0.2.2",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2342,18 +2354,18 @@ dependencies = [
|
|||
"chrono-tz",
|
||||
"colored",
|
||||
"directories",
|
||||
"getrandom",
|
||||
"getrandom 0.3.1",
|
||||
"libc",
|
||||
"libffi",
|
||||
"libloading",
|
||||
"measureme",
|
||||
"rand",
|
||||
"rand 0.9.0",
|
||||
"regex",
|
||||
"rustc_version",
|
||||
"smallvec",
|
||||
"tempfile",
|
||||
"tikv-jemalloc-sys",
|
||||
"ui_test",
|
||||
"ui_test 0.28.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
|
|
@ -2782,7 +2794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
|
||||
dependencies = [
|
||||
"phf_shared 0.10.0",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2792,7 +2804,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
||||
dependencies = [
|
||||
"phf_shared 0.11.3",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2860,7 +2872,7 @@ version = "0.2.20"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
"zerocopy 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2978,8 +2990,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.0",
|
||||
"zerocopy 0.8.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2989,7 +3012,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2998,7 +3031,17 @@ version = "0.6.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
|
||||
dependencies = [
|
||||
"getrandom 0.3.1",
|
||||
"zerocopy 0.8.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3007,7 +3050,7 @@ version = "0.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3045,7 +3088,7 @@ version = "0.4.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
|
@ -3283,7 +3326,7 @@ name = "rustc_abi"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rand_xoshiro",
|
||||
"rustc_data_structures",
|
||||
"rustc_feature",
|
||||
|
|
@ -3897,7 +3940,7 @@ dependencies = [
|
|||
name = "rustc_incremental"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -5218,7 +5261,7 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
|
|
@ -5281,8 +5324,8 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"indicatif",
|
||||
"num",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
|
|
@ -5602,7 +5645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
|
|
@ -5662,6 +5705,32 @@ dependencies = [
|
|||
"spanned",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ui_test"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7484683d60d50ca1d1b6433c3dbf6c5ad71d20387acdcfb16fe79573f3fba576"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.11.5",
|
||||
"anyhow",
|
||||
"bstr",
|
||||
"cargo-platform",
|
||||
"cargo_metadata 0.18.1",
|
||||
"color-eyre",
|
||||
"colored",
|
||||
"comma",
|
||||
"crossbeam-channel",
|
||||
"indicatif",
|
||||
"levenshtein",
|
||||
"prettydiff",
|
||||
"regex",
|
||||
"rustc_version",
|
||||
"rustfix",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"spanned",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-langid"
|
||||
version = "0.9.5"
|
||||
|
|
@ -5843,7 +5912,7 @@ version = "1.12.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5880,6 +5949,15 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.13.3+wasi-0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi-preview1-component-adapter-provider"
|
||||
version = "29.0.1"
|
||||
|
|
@ -6475,6 +6553,15 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ab703352da6a72f35c39a533526393725640575bb211f61987a2748323ad956"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.223.0"
|
||||
|
|
@ -6584,7 +6671,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
"zerocopy-derive 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468"
|
||||
dependencies = [
|
||||
"zerocopy-derive 0.8.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6598,6 +6694,17 @@ dependencies = [
|
|||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.5"
|
||||
|
|
|
|||
|
|
@ -1657,7 +1657,7 @@ impl GenBlockKind {
|
|||
}
|
||||
|
||||
/// Whether we're unwrapping or wrapping an unsafe binder
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum UnsafeBinderCastKind {
|
||||
// e.g. `&i32` -> `unsafe<'a> &'a i32`
|
||||
|
|
|
|||
|
|
@ -418,10 +418,10 @@ fn compute_hir_hash(
|
|||
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
||||
let sess = tcx.sess;
|
||||
// Queries that borrow `resolver_for_lowering`.
|
||||
tcx.ensure_with_value().output_filenames(());
|
||||
tcx.ensure_with_value().early_lint_checks(());
|
||||
tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE);
|
||||
tcx.ensure_with_value().get_lang_items(());
|
||||
tcx.ensure_done().output_filenames(());
|
||||
tcx.ensure_done().early_lint_checks(());
|
||||
tcx.ensure_done().debugger_visualizers(LOCAL_CRATE);
|
||||
tcx.ensure_done().get_lang_items(());
|
||||
let (mut resolver, krate) = tcx.resolver_for_lowering().steal();
|
||||
|
||||
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
|
||||
|
|
|
|||
|
|
@ -101,16 +101,6 @@ impl PartialConstStability {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum AllowedThroughUnstableModules {
|
||||
/// This does not get a deprecation warning. We still generally would prefer people to use the
|
||||
/// fully stable path, and a warning will likely be emitted in the future.
|
||||
WithoutDeprecation,
|
||||
/// Emit the given deprecation warning.
|
||||
WithDeprecation(Symbol),
|
||||
}
|
||||
|
||||
/// The available stability levels.
|
||||
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
|
|
@ -147,8 +137,9 @@ pub enum StabilityLevel {
|
|||
Stable {
|
||||
/// Rust release which stabilized this feature.
|
||||
since: StableSince,
|
||||
/// This is `Some` if this item allowed to be referred to on stable via unstable modules.
|
||||
allowed_through_unstable_modules: Option<AllowedThroughUnstableModules>,
|
||||
/// This is `Some` if this item allowed to be referred to on stable via unstable modules;
|
||||
/// the `Symbol` is the deprecation message printed in that case.
|
||||
allowed_through_unstable_modules: Option<Symbol>,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ use rustc_ast::MetaItem;
|
|||
use rustc_ast::attr::AttributeExt;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_data_structures::{
|
||||
AllowedThroughUnstableModules, ConstStability, DefaultBodyStability, Stability, StabilityLevel,
|
||||
StableSince, UnstableReason, VERSION_PLACEHOLDER,
|
||||
ConstStability, DefaultBodyStability, Stability, StabilityLevel, StableSince, UnstableReason,
|
||||
VERSION_PLACEHOLDER,
|
||||
};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_span::{Span, Symbol, kw, sym};
|
||||
|
||||
use crate::attributes::util::UnsupportedLiteralReason;
|
||||
use crate::{parse_version, session_diagnostics};
|
||||
|
|
@ -29,10 +29,14 @@ pub fn find_stability(
|
|||
for attr in attrs {
|
||||
match attr.name_or_empty() {
|
||||
sym::rustc_allowed_through_unstable_modules => {
|
||||
allowed_through_unstable_modules = Some(match attr.value_str() {
|
||||
Some(msg) => AllowedThroughUnstableModules::WithDeprecation(msg),
|
||||
None => AllowedThroughUnstableModules::WithoutDeprecation,
|
||||
})
|
||||
// The value is mandatory, but avoid ICEs in case such code reaches this function.
|
||||
allowed_through_unstable_modules = Some(attr.value_str().unwrap_or_else(|| {
|
||||
sess.dcx().span_delayed_bug(
|
||||
item_sp,
|
||||
"`#[rustc_allowed_through_unstable_modules]` without deprecation message",
|
||||
);
|
||||
kw::Empty
|
||||
}))
|
||||
}
|
||||
sym::unstable => {
|
||||
if stab.is_some() {
|
||||
|
|
|
|||
|
|
@ -92,9 +92,6 @@ borrowck_lifetime_constraints_error =
|
|||
borrowck_limitations_implies_static =
|
||||
due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||
|
||||
borrowck_long_type_consider_verbose = consider using `--verbose` to print the full type name to the console
|
||||
borrowck_long_type_full_path = the full type name has been written to '{$path}'
|
||||
|
||||
borrowck_move_closure_suggestion =
|
||||
consider adding 'move' keyword before the nested closure
|
||||
|
||||
|
|
|
|||
|
|
@ -289,8 +289,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
None => "value".to_owned(),
|
||||
};
|
||||
if needs_note {
|
||||
let mut path = None;
|
||||
let ty = self.infcx.tcx.short_ty_string(ty, &mut path);
|
||||
let ty = self.infcx.tcx.short_string(ty, err.long_ty_path());
|
||||
if let Some(local) = place.as_local() {
|
||||
let span = self.body.local_decls[local].source_info.span;
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
|
|
@ -306,11 +305,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
place: ¬e_msg,
|
||||
});
|
||||
};
|
||||
if let Some(path) = path {
|
||||
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
|
||||
path: path.display().to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let UseSpans::FnSelfUse {
|
||||
|
|
@ -3915,7 +3909,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Index(_) => kind,
|
||||
| ProjectionElem::Index(_)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(_) => kind,
|
||||
},
|
||||
place_ty.projection_ty(tcx, elem),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -248,7 +248,98 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
);
|
||||
err.span_label(body.source_info(drop_loc).span, message);
|
||||
|
||||
if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
|
||||
struct FindLetExpr<'hir> {
|
||||
span: Span,
|
||||
result: Option<(Span, &'hir hir::Pat<'hir>, &'hir hir::Expr<'hir>)>,
|
||||
tcx: TyCtxt<'hir>,
|
||||
}
|
||||
|
||||
impl<'hir> rustc_hir::intravisit::Visitor<'hir> for FindLetExpr<'hir> {
|
||||
type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.tcx.hir()
|
||||
}
|
||||
fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
|
||||
if let hir::ExprKind::If(cond, _conseq, _alt)
|
||||
| hir::ExprKind::Loop(
|
||||
hir::Block {
|
||||
expr:
|
||||
Some(&hir::Expr {
|
||||
kind: hir::ExprKind::If(cond, _conseq, _alt),
|
||||
..
|
||||
}),
|
||||
..
|
||||
},
|
||||
_,
|
||||
hir::LoopSource::While,
|
||||
_,
|
||||
) = expr.kind
|
||||
&& let hir::ExprKind::Let(hir::LetExpr {
|
||||
init: let_expr_init,
|
||||
span: let_expr_span,
|
||||
pat: let_expr_pat,
|
||||
..
|
||||
}) = cond.kind
|
||||
&& let_expr_init.span.contains(self.span)
|
||||
{
|
||||
self.result =
|
||||
Some((*let_expr_span, let_expr_pat, let_expr_init))
|
||||
} else {
|
||||
hir::intravisit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let &LocalInfo::IfThenRescopeTemp { if_then } = local_decl.local_info()
|
||||
&& let hir::Node::Expr(expr) = tcx.hir_node(if_then)
|
||||
&& let hir::ExprKind::If(cond, conseq, alt) = expr.kind
|
||||
&& let hir::ExprKind::Let(&hir::LetExpr {
|
||||
span: _,
|
||||
pat,
|
||||
init,
|
||||
// FIXME(#101728): enable rewrite when type ascription is
|
||||
// stabilized again.
|
||||
ty: None,
|
||||
recovered: _,
|
||||
}) = cond.kind
|
||||
&& pat.span.can_be_used_for_suggestions()
|
||||
&& let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
|
||||
{
|
||||
suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
|
||||
} else if let Some((old, new)) = multiple_borrow_span
|
||||
&& let def_id = body.source.def_id()
|
||||
&& let Some(node) = tcx.hir().get_if_local(def_id)
|
||||
&& let Some(body_id) = node.body_id()
|
||||
&& let hir_body = tcx.hir().body(body_id)
|
||||
&& let mut expr_finder = (FindLetExpr { span: old, result: None, tcx })
|
||||
&& let Some((let_expr_span, let_expr_pat, let_expr_init)) = {
|
||||
expr_finder.visit_expr(hir_body.value);
|
||||
expr_finder.result
|
||||
}
|
||||
&& !let_expr_span.contains(new)
|
||||
{
|
||||
// #133941: The `old` expression is at the conditional part of an
|
||||
// if/while let expression. Adding a semicolon won't work.
|
||||
// Instead, try suggesting the `matches!` macro or a temporary.
|
||||
if let_expr_pat
|
||||
.walk_short(|pat| !matches!(pat.kind, hir::PatKind::Binding(..)))
|
||||
{
|
||||
if let Ok(pat_snippet) =
|
||||
tcx.sess.source_map().span_to_snippet(let_expr_pat.span)
|
||||
&& let Ok(init_snippet) =
|
||||
tcx.sess.source_map().span_to_snippet(let_expr_init.span)
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
let_expr_span,
|
||||
"consider using the `matches!` macro",
|
||||
format!("matches!({init_snippet}, {pat_snippet})"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.note("consider using the `matches!` macro");
|
||||
}
|
||||
}
|
||||
} else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
|
||||
if info.tail_result_is_ignored {
|
||||
// #85581: If the first mutable borrow's scope contains
|
||||
// the second borrow, this suggestion isn't helpful.
|
||||
|
|
@ -281,23 +372,6 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
};
|
||||
} else if let &LocalInfo::IfThenRescopeTemp { if_then } =
|
||||
local_decl.local_info()
|
||||
&& let hir::Node::Expr(expr) = tcx.hir_node(if_then)
|
||||
&& let hir::ExprKind::If(cond, conseq, alt) = expr.kind
|
||||
&& let hir::ExprKind::Let(&hir::LetExpr {
|
||||
span: _,
|
||||
pat,
|
||||
init,
|
||||
// FIXME(#101728): enable rewrite when type ascription is
|
||||
// stabilized again.
|
||||
ty: None,
|
||||
recovered: _,
|
||||
}) = cond.kind
|
||||
&& pat.span.can_be_used_for_suggestions()
|
||||
&& let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
|
||||
{
|
||||
suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::collections::BTreeMap;
|
|||
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan};
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
|
||||
use rustc_hir::def::{CtorKind, Namespace};
|
||||
use rustc_hir::{self as hir, CoroutineKind, LangItem};
|
||||
use rustc_index::IndexSlice;
|
||||
|
|
@ -29,7 +29,7 @@ use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
|||
use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{
|
||||
FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
|
||||
FulfillmentError, FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
|
||||
};
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -370,6 +370,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
ProjectionElem::Downcast(..) => (),
|
||||
ProjectionElem::OpaqueCast(..) => (),
|
||||
ProjectionElem::Subtype(..) => (),
|
||||
ProjectionElem::UnwrapUnsafeBinder(_) => (),
|
||||
ProjectionElem::Field(field, _ty) => {
|
||||
// FIXME(project-rfc_2229#36): print capture precisely here.
|
||||
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
|
||||
|
|
@ -450,9 +451,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
|
||||
}
|
||||
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
|
||||
ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => {
|
||||
PlaceTy::from_ty(*ty)
|
||||
}
|
||||
ProjectionElem::Subtype(ty)
|
||||
| ProjectionElem::OpaqueCast(ty)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty),
|
||||
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
|
||||
},
|
||||
};
|
||||
|
|
@ -1433,17 +1434,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
error.obligation.predicate,
|
||||
)
|
||||
}
|
||||
[errors @ .., last] => {
|
||||
_ => {
|
||||
format!(
|
||||
"you could `clone` the value and consume it, if the \
|
||||
following trait bounds could be satisfied: \
|
||||
{} and `{}`",
|
||||
errors
|
||||
.iter()
|
||||
.map(|e| format!("`{}`", e.obligation.predicate))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
last.obligation.predicate,
|
||||
following trait bounds could be satisfied: {}",
|
||||
listify(&errors, |e: &FulfillmentError<'tcx>| format!(
|
||||
"`{}`",
|
||||
e.obligation.predicate
|
||||
))
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -596,19 +596,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.suggest_cloning(err, place_ty, expr, None);
|
||||
}
|
||||
|
||||
let mut path = None;
|
||||
let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
|
||||
let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path());
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
});
|
||||
if let Some(path) = path {
|
||||
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
|
||||
path: path.display().to_string(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
binds_to.sort();
|
||||
binds_to.dedup();
|
||||
|
|
@ -635,19 +629,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.suggest_cloning(err, place_ty, expr, Some(use_spans));
|
||||
}
|
||||
|
||||
let mut path = None;
|
||||
let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
|
||||
let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path());
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty,
|
||||
place: &place_desc,
|
||||
span: use_span,
|
||||
});
|
||||
if let Some(path) = path {
|
||||
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
|
||||
path: path.display().to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
use_spans.args_subdiag(err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
|
||||
|
|
@ -845,19 +833,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.suggest_cloning(err, bind_to.ty, expr, None);
|
||||
}
|
||||
|
||||
let mut path = None;
|
||||
let ty = self.infcx.tcx.short_ty_string(bind_to.ty, &mut path);
|
||||
let ty = self.infcx.tcx.short_string(bind_to.ty, err.long_ty_path());
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty,
|
||||
place: place_desc,
|
||||
span: binding_span,
|
||||
});
|
||||
if let Some(path) = path {
|
||||
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
|
||||
path: path.display().to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -167,7 +167,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::OpaqueCast { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Downcast(..),
|
||||
| ProjectionElem::Downcast(..)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(_),
|
||||
],
|
||||
} => bug!("Unexpected immutable place."),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1398,6 +1398,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
self.consume_operand(location, (operand, span), state);
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::WrapUnsafeBinder(op, _) => {
|
||||
self.consume_operand(location, (op, span), state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1770,7 +1774,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
// So it's safe to skip these.
|
||||
ProjectionElem::OpaqueCast(_)
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Downcast(_, _) => (),
|
||||
| ProjectionElem::Downcast(_, _)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(_) => (),
|
||||
}
|
||||
|
||||
place_ty = place_ty.projection_ty(tcx, elem);
|
||||
|
|
@ -2004,6 +2009,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
// FIXME: is this true even if P is an adt with a dtor?
|
||||
{ }
|
||||
|
||||
ProjectionElem::UnwrapUnsafeBinder(_) => {
|
||||
check_parent_of_field(self, location, place_base, span, state);
|
||||
}
|
||||
|
||||
// assigning to (*P) requires P to be initialized
|
||||
ProjectionElem::Deref => {
|
||||
self.check_if_full_path_is_moved(
|
||||
|
|
@ -2384,7 +2393,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Subtype(..)
|
||||
| ProjectionElem::OpaqueCast { .. }
|
||||
| ProjectionElem::Downcast(..) => {
|
||||
| ProjectionElem::Downcast(..)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(_) => {
|
||||
let upvar_field_projection = self.is_upvar_field_projection(place);
|
||||
if let Some(field) = upvar_field_projection {
|
||||
let upvar = &self.upvars[field.index()];
|
||||
|
|
|
|||
|
|
@ -250,7 +250,8 @@ fn place_components_conflict<'tcx>(
|
|||
| (ProjectionElem::Subslice { .. }, _, _)
|
||||
| (ProjectionElem::OpaqueCast { .. }, _, _)
|
||||
| (ProjectionElem::Subtype(_), _, _)
|
||||
| (ProjectionElem::Downcast { .. }, _, _) => {
|
||||
| (ProjectionElem::Downcast { .. }, _, _)
|
||||
| (ProjectionElem::UnwrapUnsafeBinder(_), _, _) => {
|
||||
// Recursive case. This can still be disjoint on a
|
||||
// further iteration if this a shallow access and
|
||||
// there's a deref later on, e.g., a borrow
|
||||
|
|
@ -519,5 +520,9 @@ fn place_projection_conflict<'tcx>(
|
|||
pi1_elem,
|
||||
pi2_elem
|
||||
),
|
||||
|
||||
(ProjectionElem::UnwrapUnsafeBinder(_), _) => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -325,6 +325,10 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
self.consume_operand(location, operand);
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::WrapUnsafeBinder(op, _) => {
|
||||
self.consume_operand(location, op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
|
|||
self.next = Some(cursor_base);
|
||||
return Some(cursor);
|
||||
}
|
||||
ProjectionElem::UnwrapUnsafeBinder(_) => {
|
||||
self.next = Some(cursor_base);
|
||||
return Some(cursor);
|
||||
}
|
||||
ProjectionElem::Downcast(..)
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::OpaqueCast { .. }
|
||||
|
|
|
|||
|
|
@ -458,13 +458,6 @@ pub(crate) enum OnClosureNote<'a> {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(borrowck_long_type_full_path)]
|
||||
#[note(borrowck_long_type_consider_verbose)]
|
||||
pub(crate) struct LongTypePath {
|
||||
pub(crate) path: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum TypeNoCopy<'a> {
|
||||
#[label(borrowck_ty_no_impl_copy)]
|
||||
|
|
|
|||
|
|
@ -302,6 +302,25 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
)
|
||||
.unwrap();
|
||||
}
|
||||
ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||
let ty::UnsafeBinder(binder_ty) = *base_ty.ty.kind() else {
|
||||
unreachable!();
|
||||
};
|
||||
let found_ty = self.typeck.infcx.instantiate_binder_with_fresh_vars(
|
||||
self.body().source_info(location).span,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
binder_ty.into(),
|
||||
);
|
||||
self.typeck
|
||||
.relate_types(
|
||||
ty,
|
||||
context.ambient_variance(),
|
||||
found_ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
ProjectionElem::Subtype(_) => {
|
||||
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
|
||||
}
|
||||
|
|
@ -2233,6 +2252,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.check_operand(right, location);
|
||||
}
|
||||
|
||||
Rvalue::WrapUnsafeBinder(op, ty) => {
|
||||
self.check_operand(op, location);
|
||||
let operand_ty = op.ty(self.body, self.tcx());
|
||||
|
||||
let ty::UnsafeBinder(binder_ty) = *ty.kind() else {
|
||||
unreachable!();
|
||||
};
|
||||
let expected_ty = self.infcx.instantiate_binder_with_fresh_vars(
|
||||
self.body().source_info(location).span,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
binder_ty.into(),
|
||||
);
|
||||
self.sub_types(
|
||||
operand_ty,
|
||||
expected_ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Rvalue::RawPtr(..)
|
||||
| Rvalue::ThreadLocalRef(..)
|
||||
| Rvalue::Len(..)
|
||||
|
|
@ -2258,7 +2298,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
| Rvalue::NullaryOp(..)
|
||||
| Rvalue::CopyForDeref(..)
|
||||
| Rvalue::UnaryOp(..)
|
||||
| Rvalue::Discriminant(..) => None,
|
||||
| Rvalue::Discriminant(..)
|
||||
| Rvalue::WrapUnsafeBinder(..) => None,
|
||||
|
||||
Rvalue::Aggregate(aggregate, _) => match **aggregate {
|
||||
AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
|
||||
|
|
@ -2450,7 +2491,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
| ProjectionElem::OpaqueCast(..)
|
||||
| ProjectionElem::Index(..)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. } => {
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::UnwrapUnsafeBinder(_) => {
|
||||
// other field access
|
||||
}
|
||||
ProjectionElem::Subtype(_) => {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) ->
|
|||
|
||||
let (ident, vdata, fields) = match substr.fields {
|
||||
Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
|
||||
EnumMatching(_, v, fields) => (v.ident, &v.data, fields),
|
||||
EnumMatching(v, fields) => (v.ident, &v.data, fields),
|
||||
AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
|
||||
EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => {
|
||||
cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
|
||||
|
|
|
|||
|
|
@ -1,215 +0,0 @@
|
|||
//! The compiler code necessary for `#[derive(RustcDecodable)]`. See encodable.rs for more.
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, Expr, MetaItem, Mutability};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::deriving::pathvec_std;
|
||||
|
||||
pub(crate) fn expand_deriving_rustc_decodable(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
mitem: &MetaItem,
|
||||
item: &Annotatable,
|
||||
push: &mut dyn FnMut(Annotatable),
|
||||
is_const: bool,
|
||||
) {
|
||||
let krate = sym::rustc_serialize;
|
||||
let typaram = sym::__D;
|
||||
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods: vec![MethodDef {
|
||||
name: sym::decode,
|
||||
generics: Bounds {
|
||||
bounds: vec![(typaram, vec![Path::new_(
|
||||
vec![krate, sym::Decoder],
|
||||
vec![],
|
||||
PathKind::Global,
|
||||
)])],
|
||||
},
|
||||
explicit_self: false,
|
||||
nonself_args: vec![(
|
||||
Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut),
|
||||
sym::d,
|
||||
)],
|
||||
ret_ty: Path(Path::new_(
|
||||
pathvec_std!(result::Result),
|
||||
vec![
|
||||
Box::new(Self_),
|
||||
Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
|
||||
],
|
||||
PathKind::Std,
|
||||
)),
|
||||
attributes: ast::AttrVec::new(),
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
decodable_substructure(a, b, c, krate)
|
||||
})),
|
||||
}],
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
};
|
||||
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
||||
fn decodable_substructure(
|
||||
cx: &ExtCtxt<'_>,
|
||||
trait_span: Span,
|
||||
substr: &Substructure<'_>,
|
||||
krate: Symbol,
|
||||
) -> BlockOrExpr {
|
||||
let decoder = substr.nonselflike_args[0].clone();
|
||||
let recurse = vec![
|
||||
Ident::new(krate, trait_span),
|
||||
Ident::new(sym::Decodable, trait_span),
|
||||
Ident::new(sym::decode, trait_span),
|
||||
];
|
||||
let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
|
||||
// throw an underscore in front to suppress unused variable warnings
|
||||
let blkarg = Ident::new(sym::_d, trait_span);
|
||||
let blkdecoder = cx.expr_ident(trait_span, blkarg);
|
||||
|
||||
let expr = match substr.fields {
|
||||
StaticStruct(_, summary) => {
|
||||
let nfields = match summary {
|
||||
Unnamed(fields, _) => fields.len(),
|
||||
Named(fields) => fields.len(),
|
||||
};
|
||||
let fn_read_struct_field_path: Vec<_> =
|
||||
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct_field]);
|
||||
|
||||
let path = cx.path_ident(trait_span, substr.type_ident);
|
||||
let result =
|
||||
decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| {
|
||||
cx.expr_try(
|
||||
span,
|
||||
cx.expr_call_global(span, fn_read_struct_field_path.clone(), thin_vec![
|
||||
blkdecoder.clone(),
|
||||
cx.expr_str(span, name),
|
||||
cx.expr_usize(span, field),
|
||||
exprdecode.clone(),
|
||||
]),
|
||||
)
|
||||
});
|
||||
let result = cx.expr_ok(trait_span, result);
|
||||
let fn_read_struct_path: Vec<_> =
|
||||
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct]);
|
||||
|
||||
cx.expr_call_global(trait_span, fn_read_struct_path, thin_vec![
|
||||
decoder,
|
||||
cx.expr_str(trait_span, substr.type_ident.name),
|
||||
cx.expr_usize(trait_span, nfields),
|
||||
cx.lambda1(trait_span, result, blkarg),
|
||||
])
|
||||
}
|
||||
StaticEnum(_, fields) => {
|
||||
let variant = Ident::new(sym::i, trait_span);
|
||||
|
||||
let mut arms = ThinVec::with_capacity(fields.len() + 1);
|
||||
let mut variants = ThinVec::with_capacity(fields.len());
|
||||
|
||||
let fn_read_enum_variant_arg_path: Vec<_> =
|
||||
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant_arg]);
|
||||
|
||||
for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
|
||||
variants.push(cx.expr_str(v_span, ident.name));
|
||||
|
||||
let path = cx.path(trait_span, vec![substr.type_ident, ident]);
|
||||
let decoded =
|
||||
decode_static_fields(cx, v_span, path, parts, |cx, span, _, field| {
|
||||
let idx = cx.expr_usize(span, field);
|
||||
cx.expr_try(
|
||||
span,
|
||||
cx.expr_call_global(
|
||||
span,
|
||||
fn_read_enum_variant_arg_path.clone(),
|
||||
thin_vec![blkdecoder.clone(), idx, exprdecode.clone()],
|
||||
),
|
||||
)
|
||||
});
|
||||
|
||||
arms.push(cx.arm(v_span, cx.pat_lit(v_span, cx.expr_usize(v_span, i)), decoded));
|
||||
}
|
||||
|
||||
arms.push(cx.arm_unreachable(trait_span));
|
||||
|
||||
let result = cx.expr_ok(
|
||||
trait_span,
|
||||
cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms),
|
||||
);
|
||||
let lambda = cx.lambda(trait_span, vec![blkarg, variant], result);
|
||||
let variant_array_ref = cx.expr_array_ref(trait_span, variants);
|
||||
let fn_read_enum_variant_path: Vec<_> =
|
||||
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant]);
|
||||
let result = cx.expr_call_global(trait_span, fn_read_enum_variant_path, thin_vec![
|
||||
blkdecoder,
|
||||
variant_array_ref,
|
||||
lambda
|
||||
]);
|
||||
let fn_read_enum_path: Vec<_> =
|
||||
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]);
|
||||
|
||||
cx.expr_call_global(trait_span, fn_read_enum_path, thin_vec![
|
||||
decoder,
|
||||
cx.expr_str(trait_span, substr.type_ident.name),
|
||||
cx.lambda1(trait_span, result, blkarg),
|
||||
])
|
||||
}
|
||||
_ => cx.dcx().bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
|
||||
};
|
||||
BlockOrExpr::new_expr(expr)
|
||||
}
|
||||
|
||||
/// Creates a decoder for a single enum variant/struct:
|
||||
/// - `outer_pat_path` is the path to this enum variant/struct
|
||||
/// - `getarg` should retrieve the `usize`-th field with name `@str`.
|
||||
fn decode_static_fields<F>(
|
||||
cx: &ExtCtxt<'_>,
|
||||
trait_span: Span,
|
||||
outer_pat_path: ast::Path,
|
||||
fields: &StaticFields,
|
||||
mut getarg: F,
|
||||
) -> P<Expr>
|
||||
where
|
||||
F: FnMut(&ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>,
|
||||
{
|
||||
match fields {
|
||||
Unnamed(fields, is_tuple) => {
|
||||
let path_expr = cx.expr_path(outer_pat_path);
|
||||
if matches!(is_tuple, IsTuple::No) {
|
||||
path_expr
|
||||
} else {
|
||||
let fields = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &span)| getarg(cx, span, Symbol::intern(&format!("_field{i}")), i))
|
||||
.collect();
|
||||
|
||||
cx.expr_call(trait_span, path_expr, fields)
|
||||
}
|
||||
}
|
||||
Named(fields) => {
|
||||
// use the field's span to get nicer error messages.
|
||||
let fields = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &(ident, span, _))| {
|
||||
let arg = getarg(cx, span, ident.name, i);
|
||||
cx.field_imm(span, ident, arg)
|
||||
})
|
||||
.collect();
|
||||
cx.expr_struct(trait_span, outer_pat_path, fields)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,7 +42,7 @@ pub(crate) fn expand_deriving_default(
|
|||
StaticStruct(_, fields) => {
|
||||
default_struct_substructure(cx, trait_span, substr, fields)
|
||||
}
|
||||
StaticEnum(enum_def, _) => {
|
||||
StaticEnum(enum_def) => {
|
||||
default_enum_substructure(cx, trait_span, enum_def, item.span())
|
||||
}
|
||||
_ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"),
|
||||
|
|
|
|||
|
|
@ -1,284 +0,0 @@
|
|||
//! The compiler code necessary to implement the `#[derive(RustcEncodable)]`
|
||||
//! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that
|
||||
//! type-defining items may be tagged with
|
||||
//! `#[derive(RustcEncodable, RustcDecodable)]`.
|
||||
//!
|
||||
//! For example, a type like:
|
||||
//!
|
||||
//! ```ignore (old code)
|
||||
//! #[derive(RustcEncodable, RustcDecodable)]
|
||||
//! struct Node { id: usize }
|
||||
//! ```
|
||||
//!
|
||||
//! would generate two implementations like:
|
||||
//!
|
||||
//! ```ignore (old code)
|
||||
//! # struct Node { id: usize }
|
||||
//! impl<S: Encoder<E>, E> Encodable<S, E> for Node {
|
||||
//! fn encode(&self, s: &mut S) -> Result<(), E> {
|
||||
//! s.emit_struct("Node", 1, |this| {
|
||||
//! this.emit_struct_field("id", 0, |this| {
|
||||
//! Encodable::encode(&self.id, this)
|
||||
//! /* this.emit_usize(self.id) can also be used */
|
||||
//! })
|
||||
//! })
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! impl<D: Decoder<E>, E> Decodable<D, E> for Node {
|
||||
//! fn decode(d: &mut D) -> Result<Node, E> {
|
||||
//! d.read_struct("Node", 1, |this| {
|
||||
//! match this.read_struct_field("id", 0, |this| Decodable::decode(this)) {
|
||||
//! Ok(id) => Ok(Node { id: id }),
|
||||
//! Err(e) => Err(e),
|
||||
//! }
|
||||
//! })
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Other interesting scenarios are when the item has type parameters or
|
||||
//! references other non-built-in types. A type definition like:
|
||||
//!
|
||||
//! ```ignore (old code)
|
||||
//! # #[derive(RustcEncodable, RustcDecodable)]
|
||||
//! # struct Span;
|
||||
//! #[derive(RustcEncodable, RustcDecodable)]
|
||||
//! struct Spanned<T> { node: T, span: Span }
|
||||
//! ```
|
||||
//!
|
||||
//! would yield functions like:
|
||||
//!
|
||||
//! ```ignore (old code)
|
||||
//! # #[derive(RustcEncodable, RustcDecodable)]
|
||||
//! # struct Span;
|
||||
//! # struct Spanned<T> { node: T, span: Span }
|
||||
//! impl<
|
||||
//! S: Encoder<E>,
|
||||
//! E,
|
||||
//! T: Encodable<S, E>
|
||||
//! > Encodable<S, E> for Spanned<T> {
|
||||
//! fn encode(&self, s: &mut S) -> Result<(), E> {
|
||||
//! s.emit_struct("Spanned", 2, |this| {
|
||||
//! this.emit_struct_field("node", 0, |this| self.node.encode(this))
|
||||
//! .unwrap();
|
||||
//! this.emit_struct_field("span", 1, |this| self.span.encode(this))
|
||||
//! })
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! impl<
|
||||
//! D: Decoder<E>,
|
||||
//! E,
|
||||
//! T: Decodable<D, E>
|
||||
//! > Decodable<D, E> for Spanned<T> {
|
||||
//! fn decode(d: &mut D) -> Result<Spanned<T>, E> {
|
||||
//! d.read_struct("Spanned", 2, |this| {
|
||||
//! Ok(Spanned {
|
||||
//! node: this.read_struct_field("node", 0, |this| Decodable::decode(this))
|
||||
//! .unwrap(),
|
||||
//! span: this.read_struct_field("span", 1, |this| Decodable::decode(this))
|
||||
//! .unwrap(),
|
||||
//! })
|
||||
//! })
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::deriving::pathvec_std;
|
||||
|
||||
pub(crate) fn expand_deriving_rustc_encodable(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
mitem: &MetaItem,
|
||||
item: &Annotatable,
|
||||
push: &mut dyn FnMut(Annotatable),
|
||||
is_const: bool,
|
||||
) {
|
||||
let krate = sym::rustc_serialize;
|
||||
let typaram = sym::__S;
|
||||
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods: vec![MethodDef {
|
||||
name: sym::encode,
|
||||
generics: Bounds {
|
||||
bounds: vec![(typaram, vec![Path::new_(
|
||||
vec![krate, sym::Encoder],
|
||||
vec![],
|
||||
PathKind::Global,
|
||||
)])],
|
||||
},
|
||||
explicit_self: true,
|
||||
nonself_args: vec![(
|
||||
Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut),
|
||||
sym::s,
|
||||
)],
|
||||
ret_ty: Path(Path::new_(
|
||||
pathvec_std!(result::Result),
|
||||
vec![
|
||||
Box::new(Unit),
|
||||
Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
|
||||
],
|
||||
PathKind::Std,
|
||||
)),
|
||||
attributes: AttrVec::new(),
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
encodable_substructure(a, b, c, krate)
|
||||
})),
|
||||
}],
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
};
|
||||
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
||||
fn encodable_substructure(
|
||||
cx: &ExtCtxt<'_>,
|
||||
trait_span: Span,
|
||||
substr: &Substructure<'_>,
|
||||
krate: Symbol,
|
||||
) -> BlockOrExpr {
|
||||
let encoder = substr.nonselflike_args[0].clone();
|
||||
// throw an underscore in front to suppress unused variable warnings
|
||||
let blkarg = Ident::new(sym::_e, trait_span);
|
||||
let blkencoder = cx.expr_ident(trait_span, blkarg);
|
||||
let fn_path = cx.expr_path(cx.path_global(trait_span, vec![
|
||||
Ident::new(krate, trait_span),
|
||||
Ident::new(sym::Encodable, trait_span),
|
||||
Ident::new(sym::encode, trait_span),
|
||||
]));
|
||||
|
||||
match substr.fields {
|
||||
Struct(_, fields) => {
|
||||
let fn_emit_struct_field_path =
|
||||
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]);
|
||||
let mut stmts = ThinVec::new();
|
||||
for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() {
|
||||
let name = match name {
|
||||
Some(id) => id.name,
|
||||
None => Symbol::intern(&format!("_field{i}")),
|
||||
};
|
||||
let self_ref = cx.expr_addr_of(span, self_expr.clone());
|
||||
let enc =
|
||||
cx.expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]);
|
||||
let lambda = cx.lambda1(span, enc, blkarg);
|
||||
let call = cx.expr_call_global(span, fn_emit_struct_field_path.clone(), thin_vec![
|
||||
blkencoder.clone(),
|
||||
cx.expr_str(span, name),
|
||||
cx.expr_usize(span, i),
|
||||
lambda,
|
||||
]);
|
||||
|
||||
// last call doesn't need a try!
|
||||
let last = fields.len() - 1;
|
||||
let call = if i != last {
|
||||
cx.expr_try(span, call)
|
||||
} else {
|
||||
cx.expr(span, ExprKind::Ret(Some(call)))
|
||||
};
|
||||
|
||||
let stmt = cx.stmt_expr(call);
|
||||
stmts.push(stmt);
|
||||
}
|
||||
|
||||
// unit structs have no fields and need to return Ok()
|
||||
let blk = if stmts.is_empty() {
|
||||
let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new()));
|
||||
cx.lambda1(trait_span, ok, blkarg)
|
||||
} else {
|
||||
cx.lambda_stmts_1(trait_span, stmts, blkarg)
|
||||
};
|
||||
|
||||
let fn_emit_struct_path =
|
||||
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]);
|
||||
|
||||
let expr = cx.expr_call_global(trait_span, fn_emit_struct_path, thin_vec![
|
||||
encoder,
|
||||
cx.expr_str(trait_span, substr.type_ident.name),
|
||||
cx.expr_usize(trait_span, fields.len()),
|
||||
blk,
|
||||
]);
|
||||
BlockOrExpr::new_expr(expr)
|
||||
}
|
||||
|
||||
EnumMatching(idx, variant, fields) => {
|
||||
// We're not generating an AST that the borrow checker is expecting,
|
||||
// so we need to generate a unique local variable to take the
|
||||
// mutable loan out on, otherwise we get conflicts which don't
|
||||
// actually exist.
|
||||
let me = cx.stmt_let(trait_span, false, blkarg, encoder);
|
||||
let encoder = cx.expr_ident(trait_span, blkarg);
|
||||
|
||||
let fn_emit_enum_variant_arg_path: Vec<_> =
|
||||
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant_arg]);
|
||||
|
||||
let mut stmts = ThinVec::new();
|
||||
if !fields.is_empty() {
|
||||
let last = fields.len() - 1;
|
||||
for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() {
|
||||
let self_ref = cx.expr_addr_of(span, self_expr.clone());
|
||||
let enc = cx
|
||||
.expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]);
|
||||
let lambda = cx.lambda1(span, enc, blkarg);
|
||||
|
||||
let call = cx.expr_call_global(
|
||||
span,
|
||||
fn_emit_enum_variant_arg_path.clone(),
|
||||
thin_vec![blkencoder.clone(), cx.expr_usize(span, i), lambda],
|
||||
);
|
||||
let call = if i != last {
|
||||
cx.expr_try(span, call)
|
||||
} else {
|
||||
cx.expr(span, ExprKind::Ret(Some(call)))
|
||||
};
|
||||
stmts.push(cx.stmt_expr(call));
|
||||
}
|
||||
} else {
|
||||
let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new()));
|
||||
let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok)));
|
||||
stmts.push(cx.stmt_expr(ret_ok));
|
||||
}
|
||||
|
||||
let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
|
||||
let name = cx.expr_str(trait_span, variant.ident.name);
|
||||
|
||||
let fn_emit_enum_variant_path: Vec<_> =
|
||||
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant]);
|
||||
|
||||
let call = cx.expr_call_global(trait_span, fn_emit_enum_variant_path, thin_vec![
|
||||
blkencoder,
|
||||
name,
|
||||
cx.expr_usize(trait_span, *idx),
|
||||
cx.expr_usize(trait_span, fields.len()),
|
||||
blk,
|
||||
]);
|
||||
|
||||
let blk = cx.lambda1(trait_span, call, blkarg);
|
||||
let fn_emit_enum_path: Vec<_> =
|
||||
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]);
|
||||
let expr = cx.expr_call_global(trait_span, fn_emit_enum_path, thin_vec![
|
||||
encoder,
|
||||
cx.expr_str(trait_span, substr.type_ident.name),
|
||||
blk
|
||||
]);
|
||||
BlockOrExpr::new_mixed(thin_vec![me], Some(expr))
|
||||
}
|
||||
|
||||
_ => cx.dcx().bug("expected Struct or EnumMatching in derive(Encodable)"),
|
||||
}
|
||||
}
|
||||
|
|
@ -311,7 +311,7 @@ pub(crate) enum SubstructureFields<'a> {
|
|||
/// Matching variants of the enum: variant index, ast::Variant,
|
||||
/// fields: the field name is only non-`None` in the case of a struct
|
||||
/// variant.
|
||||
EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>),
|
||||
EnumMatching(&'a ast::Variant, Vec<FieldInfo>),
|
||||
|
||||
/// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as
|
||||
/// if they were fields. The second field is the expression to combine the
|
||||
|
|
@ -322,7 +322,7 @@ pub(crate) enum SubstructureFields<'a> {
|
|||
StaticStruct(&'a ast::VariantData, StaticFields),
|
||||
|
||||
/// A static method where `Self` is an enum.
|
||||
StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
|
||||
StaticEnum(&'a ast::EnumDef),
|
||||
}
|
||||
|
||||
/// Combine the values of all the fields together. The last argument is
|
||||
|
|
@ -1270,7 +1270,7 @@ impl<'a> MethodDef<'a> {
|
|||
trait_,
|
||||
type_ident,
|
||||
nonselflike_args,
|
||||
&EnumMatching(0, variant, Vec::new()),
|
||||
&EnumMatching(variant, Vec::new()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1282,9 +1282,8 @@ impl<'a> MethodDef<'a> {
|
|||
// where each tuple has length = selflike_args.len()
|
||||
let mut match_arms: ThinVec<ast::Arm> = variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, v)| !(unify_fieldless_variants && v.data.fields().is_empty()))
|
||||
.map(|(index, variant)| {
|
||||
.filter(|&v| !(unify_fieldless_variants && v.data.fields().is_empty()))
|
||||
.map(|variant| {
|
||||
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
|
||||
// (see "Final wrinkle" note below for why.)
|
||||
|
||||
|
|
@ -1316,7 +1315,7 @@ impl<'a> MethodDef<'a> {
|
|||
// expressions for referencing every field of every
|
||||
// Self arg, assuming all are instances of VariantK.
|
||||
// Build up code associated with such a case.
|
||||
let substructure = EnumMatching(index, variant, fields);
|
||||
let substructure = EnumMatching(variant, fields);
|
||||
let arm_expr = self
|
||||
.call_substructure_method(
|
||||
cx,
|
||||
|
|
@ -1344,7 +1343,7 @@ impl<'a> MethodDef<'a> {
|
|||
trait_,
|
||||
type_ident,
|
||||
nonselflike_args,
|
||||
&EnumMatching(0, v, Vec::new()),
|
||||
&EnumMatching(v, Vec::new()),
|
||||
)
|
||||
.into_expr(cx, span),
|
||||
)
|
||||
|
|
@ -1407,21 +1406,12 @@ impl<'a> MethodDef<'a> {
|
|||
type_ident: Ident,
|
||||
nonselflike_args: &[P<Expr>],
|
||||
) -> BlockOrExpr {
|
||||
let summary = enum_def
|
||||
.variants
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let sp = v.span.with_ctxt(trait_.span.ctxt());
|
||||
let summary = trait_.summarise_struct(cx, &v.data);
|
||||
(v.ident, sp, summary)
|
||||
})
|
||||
.collect();
|
||||
self.call_substructure_method(
|
||||
cx,
|
||||
trait_,
|
||||
type_ident,
|
||||
nonselflike_args,
|
||||
&StaticEnum(enum_def, summary),
|
||||
&StaticEnum(enum_def),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ pub(crate) struct Path {
|
|||
#[derive(Clone)]
|
||||
pub(crate) enum PathKind {
|
||||
Local,
|
||||
Global,
|
||||
Std,
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +56,6 @@ impl Path {
|
|||
let params = tys.map(GenericArg::Type).collect();
|
||||
|
||||
match self.kind {
|
||||
PathKind::Global => cx.path_all(span, true, idents, params),
|
||||
PathKind::Local => cx.path_all(span, false, idents, params),
|
||||
PathKind::Std => {
|
||||
let def_site = cx.with_def_site_ctxt(DUMMY_SP);
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ pub(crate) mod bounds;
|
|||
pub(crate) mod clone;
|
||||
pub(crate) mod coerce_pointee;
|
||||
pub(crate) mod debug;
|
||||
pub(crate) mod decodable;
|
||||
pub(crate) mod default;
|
||||
pub(crate) mod encodable;
|
||||
pub(crate) mod hash;
|
||||
|
||||
#[path = "cmp/eq.rs"]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ use rustc_ast::{
|
|||
token,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans};
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, pluralize,
|
||||
};
|
||||
use rustc_expand::base::*;
|
||||
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
|
||||
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
|
||||
|
|
@ -975,15 +977,11 @@ fn report_invalid_references(
|
|||
} else {
|
||||
MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect())
|
||||
};
|
||||
let arg_list = if let &[index] = &indexes[..] {
|
||||
format!("argument {index}")
|
||||
} else {
|
||||
let tail = indexes.pop().unwrap();
|
||||
format!(
|
||||
"arguments {head} and {tail}",
|
||||
head = indexes.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
|
||||
)
|
||||
};
|
||||
let arg_list = format!(
|
||||
"argument{} {}",
|
||||
pluralize!(indexes.len()),
|
||||
listify(&indexes, |i: &usize| i.to_string()).unwrap_or_default()
|
||||
);
|
||||
e = ecx.dcx().struct_span_err(
|
||||
span,
|
||||
format!("invalid reference to positional {arg_list} ({num_args_desc})"),
|
||||
|
|
|
|||
|
|
@ -132,8 +132,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
|||
Ord: ord::expand_deriving_ord,
|
||||
PartialEq: partial_eq::expand_deriving_partial_eq,
|
||||
PartialOrd: partial_ord::expand_deriving_partial_ord,
|
||||
RustcDecodable: decodable::expand_deriving_rustc_decodable,
|
||||
RustcEncodable: encodable::expand_deriving_rustc_encodable,
|
||||
CoercePointee: coerce_pointee::expand_deriving_coerce_pointee,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -925,6 +925,10 @@ fn codegen_stmt<'tcx>(
|
|||
}
|
||||
crate::discriminant::codegen_set_discriminant(fx, lval, variant_index);
|
||||
}
|
||||
Rvalue::WrapUnsafeBinder(ref operand, _to_ty) => {
|
||||
let operand = codegen_operand(fx, operand);
|
||||
lval.write_cvalue_transmute(fx, operand);
|
||||
}
|
||||
}
|
||||
}
|
||||
StatementKind::StorageLive(_)
|
||||
|
|
@ -993,7 +997,9 @@ pub(crate) fn codegen_place<'tcx>(
|
|||
cplace = cplace.place_deref(fx);
|
||||
}
|
||||
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
|
||||
PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)),
|
||||
PlaceElem::Subtype(ty) | PlaceElem::UnwrapUnsafeBinder(ty) => {
|
||||
cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty));
|
||||
}
|
||||
PlaceElem::Field(field, _ty) => {
|
||||
cplace = cplace.place_field(fx, field);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -692,7 +692,7 @@ pub(crate) fn run_aot(
|
|||
|
||||
if tcx.dep_graph.is_fully_enabled() {
|
||||
for cgu in cgus {
|
||||
tcx.ensure().codegen_unit(cgu.name());
|
||||
tcx.ensure_ok().codegen_unit(cgu.name());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -420,8 +420,14 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
let g = if val_llty == llty {
|
||||
g
|
||||
} else {
|
||||
// If we created the global with the wrong type,
|
||||
// correct the type.
|
||||
// codegen_static_initializer creates the global value just from the
|
||||
// `Allocation` data by generating one big struct value that is just
|
||||
// all the bytes and pointers after each other. This will almost never
|
||||
// match the type that the static was declared with. Unfortunately
|
||||
// we can't just LLVMConstBitCast our way out of it because that has very
|
||||
// specific rules on what can be cast. So instead of adding a new way to
|
||||
// generate static initializers that match the static's type, we picked
|
||||
// the easier option and retroactively change the type of the static item itself.
|
||||
let name = llvm::get_value_name(g).to_vec();
|
||||
llvm::set_value_name(g, b"");
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ use libc::{c_char, c_uint};
|
|||
|
||||
use super::ffi::{BasicBlock, Metadata, Module, Type, Value};
|
||||
use crate::llvm::Bool;
|
||||
|
||||
#[link(name = "llvm-wrapper", kind = "static")]
|
||||
extern "C" {
|
||||
// Enzyme
|
||||
pub fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool;
|
||||
|
|
@ -12,10 +14,13 @@ extern "C" {
|
|||
pub fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
|
||||
pub fn LLVMRustEraseInstFromParent(V: &Value);
|
||||
pub fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value;
|
||||
pub fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// Enzyme
|
||||
pub fn LLVMDumpModule(M: &Module);
|
||||
pub fn LLVMDumpValue(V: &Value);
|
||||
pub fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
|
||||
|
||||
pub fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
|
||||
pub fn LLVMGetReturnType(T: &Type) -> &Type;
|
||||
pub fn LLVMGetParams(Fnc: &Value, parms: *mut &Value);
|
||||
|
|
|
|||
|
|
@ -634,7 +634,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
// unnecessarily.
|
||||
if tcx.dep_graph.is_fully_enabled() {
|
||||
for cgu in codegen_units {
|
||||
tcx.ensure().codegen_unit(cgu.name());
|
||||
tcx.ensure_ok().codegen_unit(cgu.name());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -502,6 +502,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bug!("encountered OpaqueCast({ty}) in codegen")
|
||||
}
|
||||
mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
|
||||
mir::ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||
cg_base.project_type(bx, self.monomorphize(ty))
|
||||
}
|
||||
mir::ProjectionElem::Index(index) => {
|
||||
let index = &mir::Operand::Copy(mir::Place::from(index));
|
||||
let index = self.codegen_operand(bx, index);
|
||||
|
|
|
|||
|
|
@ -823,6 +823,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
OperandRef { val: OperandValue::Immediate(val), layout: box_layout }
|
||||
}
|
||||
mir::Rvalue::WrapUnsafeBinder(ref operand, binder_ty) => {
|
||||
let operand = self.codegen_operand(bx, operand);
|
||||
let binder_ty = self.monomorphize(binder_ty);
|
||||
let layout = bx.cx().layout_of(binder_ty);
|
||||
OperandRef { val: operand.val, layout }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1123,7 +1129,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
mir::Rvalue::Discriminant(..) |
|
||||
mir::Rvalue::NullaryOp(..) |
|
||||
mir::Rvalue::ThreadLocalRef(_) |
|
||||
mir::Rvalue::Use(..) => // (*)
|
||||
mir::Rvalue::Use(..) |
|
||||
mir::Rvalue::WrapUnsafeBinder(..) => // (*)
|
||||
true,
|
||||
// Arrays are always aggregates, so it's not worth checking anything here.
|
||||
// (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.)
|
||||
|
|
|
|||
|
|
@ -728,6 +728,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::WrapUnsafeBinder(..) => {
|
||||
// Unsafe binders are always trivial to create.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -258,6 +258,8 @@ where
|
|||
in_place::<Q, _>(cx, in_local, place.as_ref())
|
||||
}
|
||||
|
||||
Rvalue::WrapUnsafeBinder(op, _) => in_operand::<Q, _>(cx, in_local, op),
|
||||
|
||||
Rvalue::Aggregate(kind, operands) => {
|
||||
// Return early if we know that the struct or enum being constructed is always
|
||||
// qualified.
|
||||
|
|
@ -297,7 +299,8 @@ where
|
|||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Downcast(_, _)
|
||||
| ProjectionElem::Index(_) => {}
|
||||
| ProjectionElem::Index(_)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(_) => {}
|
||||
}
|
||||
|
||||
let base_ty = place_base.ty(cx.body, cx.tcx);
|
||||
|
|
|
|||
|
|
@ -202,7 +202,8 @@ where
|
|||
| mir::Rvalue::NullaryOp(..)
|
||||
| mir::Rvalue::UnaryOp(..)
|
||||
| mir::Rvalue::Discriminant(..)
|
||||
| mir::Rvalue::Aggregate(..) => {}
|
||||
| mir::Rvalue::Aggregate(..)
|
||||
| mir::Rvalue::WrapUnsafeBinder(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -381,6 +381,7 @@ where
|
|||
OpaqueCast(ty) => {
|
||||
span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
|
||||
}
|
||||
UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?,
|
||||
// We don't want anything happening here, this is here as a dummy.
|
||||
Subtype(_) => base.transmute(base.layout(), self)?,
|
||||
Field(field, _) => self.project_field(base, field.index())?,
|
||||
|
|
|
|||
|
|
@ -277,6 +277,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let discr = self.discriminant_for_variant(op.layout.ty, variant)?;
|
||||
self.write_immediate(*discr, &dest)?;
|
||||
}
|
||||
|
||||
WrapUnsafeBinder(ref op, _ty) => {
|
||||
// Constructing an unsafe binder acts like a transmute
|
||||
// since the operand's layout does not change.
|
||||
let op = self.eval_operand(op, None)?;
|
||||
self.copy_op_allow_transmute(&op, &dest)?;
|
||||
}
|
||||
}
|
||||
|
||||
trace!("{:?}", self.dump_place(&dest));
|
||||
|
|
|
|||
|
|
@ -1240,6 +1240,17 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
|
|||
self.visit_field(val, 0, &self.ecx.project_index(val, 0)?)?;
|
||||
}
|
||||
}
|
||||
ty::Pat(base, pat) => {
|
||||
// First check that the base type is valid
|
||||
self.visit_value(&val.transmute(self.ecx.layout_of(*base)?, self.ecx)?)?;
|
||||
// When you extend this match, make sure to also add tests to
|
||||
// tests/ui/type/pattern_types/validity.rs((
|
||||
match **pat {
|
||||
// Range patterns are precisely reflected into `valid_range` and thus
|
||||
// handled fully by `visit_scalar` (called below).
|
||||
ty::PatternKind::Range { .. } => {},
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// default handler
|
||||
try_validation!(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::{env, error, fmt, fs, io};
|
||||
|
||||
use rustc_session::EarlyDiagCtxt;
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
|
||||
/// Expands argfiles in command line arguments.
|
||||
#[derive(Default)]
|
||||
|
|
@ -118,22 +117,22 @@ pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<Stri
|
|||
///
|
||||
/// This function is identical to [`env::args()`] except that it emits an error when it encounters
|
||||
/// non-Unicode arguments instead of panicking.
|
||||
pub fn raw_args(early_dcx: &EarlyDiagCtxt) -> Result<Vec<String>, ErrorGuaranteed> {
|
||||
let mut res = Ok(Vec::new());
|
||||
pub fn raw_args(early_dcx: &EarlyDiagCtxt) -> Vec<String> {
|
||||
let mut args = Vec::new();
|
||||
let mut guar = Ok(());
|
||||
for (i, arg) in env::args_os().enumerate() {
|
||||
match arg.into_string() {
|
||||
Ok(arg) => {
|
||||
if let Ok(args) = &mut res {
|
||||
args.push(arg);
|
||||
}
|
||||
}
|
||||
Ok(arg) => args.push(arg),
|
||||
Err(arg) => {
|
||||
res =
|
||||
guar =
|
||||
Err(early_dcx.early_err(format!("argument {i} is not valid Unicode: {arg:?}")))
|
||||
}
|
||||
}
|
||||
}
|
||||
res
|
||||
if let Err(guar) = guar {
|
||||
guar.raise_fatal();
|
||||
}
|
||||
args
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
|
|||
if let Some(pp_mode) = sess.opts.pretty {
|
||||
if pp_mode.needs_ast_map() {
|
||||
create_and_enter_global_ctxt(compiler, krate, |tcx| {
|
||||
tcx.ensure().early_lint_checks(());
|
||||
tcx.ensure_ok().early_lint_checks(());
|
||||
pretty::print(sess, pp_mode, pretty::PrintExtra::NeedsAstMap { tcx });
|
||||
passes::write_dep_info(tcx);
|
||||
});
|
||||
|
|
@ -365,7 +365,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
|
|||
return early_exit();
|
||||
}
|
||||
|
||||
tcx.ensure().analysis(());
|
||||
tcx.ensure_ok().analysis(());
|
||||
|
||||
if callbacks.after_analysis(compiler, tcx) == Compilation::Stop {
|
||||
return early_exit();
|
||||
|
|
@ -1212,9 +1212,9 @@ pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, FatalError> {
|
|||
|
||||
/// Variant of `catch_fatal_errors` for the `interface::Result` return type
|
||||
/// that also computes the exit code.
|
||||
pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
|
||||
pub fn catch_with_exit_code(f: impl FnOnce()) -> i32 {
|
||||
match catch_fatal_errors(f) {
|
||||
Ok(Ok(())) => EXIT_SUCCESS,
|
||||
Ok(()) => EXIT_SUCCESS,
|
||||
_ => EXIT_FAILURE,
|
||||
}
|
||||
}
|
||||
|
|
@ -1499,10 +1499,8 @@ pub fn main() -> ! {
|
|||
install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
|
||||
install_ctrlc_handler();
|
||||
|
||||
let exit_code = catch_with_exit_code(|| {
|
||||
run_compiler(&args::raw_args(&early_dcx)?, &mut callbacks);
|
||||
Ok(())
|
||||
});
|
||||
let exit_code =
|
||||
catch_with_exit_code(|| run_compiler(&args::raw_args(&early_dcx), &mut callbacks));
|
||||
|
||||
if let Some(format) = callbacks.time_passes {
|
||||
let end_rss = get_resident_set_size();
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ impl<'tcx> PrintExtra<'tcx> {
|
|||
|
||||
pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
|
||||
if ppm.needs_analysis() {
|
||||
ex.tcx().ensure().analysis(());
|
||||
ex.tcx().ensure_ok().analysis(());
|
||||
}
|
||||
|
||||
let (src, src_name) = get_source(sess);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher};
|
|||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::panic;
|
||||
use std::path::PathBuf;
|
||||
use std::thread::panicking;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
|
|
@ -301,6 +302,7 @@ pub struct DiagInner {
|
|||
|
||||
pub is_lint: Option<IsLint>,
|
||||
|
||||
pub long_ty_path: Option<PathBuf>,
|
||||
/// With `-Ztrack_diagnostics` enabled,
|
||||
/// we print where in rustc this error was emitted.
|
||||
pub(crate) emitted_at: DiagLocation,
|
||||
|
|
@ -324,6 +326,7 @@ impl DiagInner {
|
|||
args: Default::default(),
|
||||
sort_span: DUMMY_SP,
|
||||
is_lint: None,
|
||||
long_ty_path: None,
|
||||
emitted_at: DiagLocation::caller(),
|
||||
}
|
||||
}
|
||||
|
|
@ -641,7 +644,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
found_label: &dyn fmt::Display,
|
||||
found: DiagStyledString,
|
||||
) -> &mut Self {
|
||||
self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"")
|
||||
self.note_expected_found_extra(
|
||||
expected_label,
|
||||
expected,
|
||||
found_label,
|
||||
found,
|
||||
DiagStyledString::normal(""),
|
||||
DiagStyledString::normal(""),
|
||||
)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
|
|
@ -651,8 +661,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
expected: DiagStyledString,
|
||||
found_label: &dyn fmt::Display,
|
||||
found: DiagStyledString,
|
||||
expected_extra: &dyn fmt::Display,
|
||||
found_extra: &dyn fmt::Display,
|
||||
expected_extra: DiagStyledString,
|
||||
found_extra: DiagStyledString,
|
||||
) -> &mut Self {
|
||||
let expected_label = expected_label.to_string();
|
||||
let expected_label = if expected_label.is_empty() {
|
||||
|
|
@ -677,10 +687,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
expected_label
|
||||
))];
|
||||
msg.extend(expected.0);
|
||||
msg.push(StringPart::normal(format!("`{expected_extra}\n")));
|
||||
msg.push(StringPart::normal(format!("`")));
|
||||
msg.extend(expected_extra.0);
|
||||
msg.push(StringPart::normal(format!("\n")));
|
||||
msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
|
||||
msg.extend(found.0);
|
||||
msg.push(StringPart::normal(format!("`{found_extra}")));
|
||||
msg.push(StringPart::normal(format!("`")));
|
||||
msg.extend(found_extra.0);
|
||||
|
||||
// For now, just attach these as notes.
|
||||
self.highlighted_note(msg);
|
||||
|
|
@ -1293,9 +1306,37 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
/// `cancel`, etc. Afterwards, `drop` is the only code that will be run on
|
||||
/// `self`.
|
||||
fn take_diag(&mut self) -> DiagInner {
|
||||
if let Some(path) = &self.long_ty_path {
|
||||
self.note(format!(
|
||||
"the full name for the type has been written to '{}'",
|
||||
path.display()
|
||||
));
|
||||
self.note("consider using `--verbose` to print the full type name to the console");
|
||||
}
|
||||
Box::into_inner(self.diag.take().unwrap())
|
||||
}
|
||||
|
||||
/// This method allows us to access the path of the file where "long types" are written to.
|
||||
///
|
||||
/// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set,
|
||||
/// and if it has been then we add a note mentioning the file where the "long types" were
|
||||
/// written to.
|
||||
///
|
||||
/// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing
|
||||
/// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that
|
||||
/// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the
|
||||
/// user where we wrote the file to is only printed once at most, *and* it makes it much harder
|
||||
/// to forget to set it.
|
||||
///
|
||||
/// If the diagnostic hasn't been created before a "short ty string" is created, then you should
|
||||
/// ensure that this method is called to set it `*diag.long_ty_path() = path`.
|
||||
///
|
||||
/// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a
|
||||
/// scope, `diag.long_ty_path()` should be called once somewhere close by.
|
||||
pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
|
||||
&mut self.long_ty_path
|
||||
}
|
||||
|
||||
/// Most `emit_producing_guarantee` functions use this as a starting point.
|
||||
fn emit_producing_nothing(mut self) {
|
||||
let diag = self.take_diag();
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ use crate::snippet::{
|
|||
use crate::styled_buffer::StyledBuffer;
|
||||
use crate::translation::{Translate, to_fluent_args};
|
||||
use crate::{
|
||||
CodeSuggestion, DiagCtxt, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle,
|
||||
Level, MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl,
|
||||
CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level,
|
||||
MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl,
|
||||
};
|
||||
|
||||
/// Default column width, used in tests and when terminal dimensions cannot be determined.
|
||||
|
|
@ -537,11 +537,10 @@ impl Emitter for HumanEmitter {
|
|||
}
|
||||
|
||||
/// An emitter that does nothing when emitting a non-fatal diagnostic.
|
||||
/// Fatal diagnostics are forwarded to `fatal_dcx` to avoid silent
|
||||
/// Fatal diagnostics are forwarded to `fatal_emitter` to avoid silent
|
||||
/// failures of rustc, as witnessed e.g. in issue #89358.
|
||||
pub struct SilentEmitter {
|
||||
pub fallback_bundle: LazyFallbackBundle,
|
||||
pub fatal_dcx: DiagCtxt,
|
||||
pub fatal_emitter: Box<dyn Emitter + DynSend>,
|
||||
pub fatal_note: Option<String>,
|
||||
pub emit_fatal_diagnostic: bool,
|
||||
}
|
||||
|
|
@ -552,9 +551,7 @@ impl Translate for SilentEmitter {
|
|||
}
|
||||
|
||||
fn fallback_fluent_bundle(&self) -> &FluentBundle {
|
||||
// Ideally this field wouldn't be necessary and the fallback bundle in `fatal_dcx` would be
|
||||
// used but the lock prevents this.
|
||||
&self.fallback_bundle
|
||||
self.fatal_emitter.fallback_fluent_bundle()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -563,12 +560,12 @@ impl Emitter for SilentEmitter {
|
|||
None
|
||||
}
|
||||
|
||||
fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) {
|
||||
fn emit_diagnostic(&mut self, mut diag: DiagInner, registry: &Registry) {
|
||||
if self.emit_fatal_diagnostic && diag.level == Level::Fatal {
|
||||
if let Some(fatal_note) = &self.fatal_note {
|
||||
diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new());
|
||||
}
|
||||
self.fatal_dcx.handle().emit_diagnostic(diag);
|
||||
self.fatal_emitter.emit_diagnostic(diag, registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,13 +59,13 @@ use emitter::{DynEmitter, Emitter, is_case_difference, is_different};
|
|||
use rustc_data_structures::AtomicRef;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
|
||||
use rustc_data_structures::sync::Lock;
|
||||
use rustc_data_structures::sync::{DynSend, Lock};
|
||||
pub use rustc_error_messages::{
|
||||
DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel,
|
||||
SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
|
||||
};
|
||||
use rustc_lint_defs::LintExpectationId;
|
||||
pub use rustc_lint_defs::{Applicability, pluralize};
|
||||
pub use rustc_lint_defs::{Applicability, listify, pluralize};
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
pub use rustc_span::ErrorGuaranteed;
|
||||
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
|
||||
|
|
@ -676,57 +676,44 @@ impl DiagCtxt {
|
|||
Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
|
||||
}
|
||||
|
||||
pub fn make_silent(
|
||||
&self,
|
||||
fallback_bundle: LazyFallbackBundle,
|
||||
fatal_note: Option<String>,
|
||||
emit_fatal_diagnostic: bool,
|
||||
) {
|
||||
self.wrap_emitter(|old_dcx| {
|
||||
Box::new(emitter::SilentEmitter {
|
||||
fallback_bundle,
|
||||
fatal_dcx: DiagCtxt { inner: Lock::new(old_dcx) },
|
||||
fatal_note,
|
||||
emit_fatal_diagnostic,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn wrap_emitter<F>(&self, f: F)
|
||||
where
|
||||
F: FnOnce(DiagCtxtInner) -> Box<DynEmitter>,
|
||||
{
|
||||
// A empty type that implements `Emitter` so that a `DiagCtxtInner` can be constructed
|
||||
// to temporarily swap in place of the real one, which will be used in constructing
|
||||
// its replacement.
|
||||
pub fn make_silent(&self, fatal_note: Option<String>, emit_fatal_diagnostic: bool) {
|
||||
// An empty type that implements `Emitter` to temporarily swap in place of the real one,
|
||||
// which will be used in constructing its replacement.
|
||||
struct FalseEmitter;
|
||||
|
||||
impl Emitter for FalseEmitter {
|
||||
fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) {
|
||||
unimplemented!("false emitter must only used during `wrap_emitter`")
|
||||
unimplemented!("false emitter must only used during `make_silent`")
|
||||
}
|
||||
|
||||
fn source_map(&self) -> Option<&SourceMap> {
|
||||
unimplemented!("false emitter must only used during `wrap_emitter`")
|
||||
unimplemented!("false emitter must only used during `make_silent`")
|
||||
}
|
||||
}
|
||||
|
||||
impl translation::Translate for FalseEmitter {
|
||||
fn fluent_bundle(&self) -> Option<&FluentBundle> {
|
||||
unimplemented!("false emitter must only used during `wrap_emitter`")
|
||||
unimplemented!("false emitter must only used during `make_silent`")
|
||||
}
|
||||
|
||||
fn fallback_fluent_bundle(&self) -> &FluentBundle {
|
||||
unimplemented!("false emitter must only used during `wrap_emitter`")
|
||||
unimplemented!("false emitter must only used during `make_silent`")
|
||||
}
|
||||
}
|
||||
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let mut prev_dcx = DiagCtxtInner::new(Box::new(FalseEmitter));
|
||||
std::mem::swap(&mut *inner, &mut prev_dcx);
|
||||
let new_emitter = f(prev_dcx);
|
||||
let mut new_dcx = DiagCtxtInner::new(new_emitter);
|
||||
std::mem::swap(&mut *inner, &mut new_dcx);
|
||||
let mut prev_emitter = Box::new(FalseEmitter) as Box<dyn Emitter + DynSend>;
|
||||
std::mem::swap(&mut inner.emitter, &mut prev_emitter);
|
||||
let new_emitter = Box::new(emitter::SilentEmitter {
|
||||
fatal_emitter: prev_emitter,
|
||||
fatal_note,
|
||||
emit_fatal_diagnostic,
|
||||
});
|
||||
inner.emitter = new_emitter;
|
||||
}
|
||||
|
||||
pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
|
||||
self.inner.borrow_mut().emitter = emitter;
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`.
|
||||
|
|
@ -1999,18 +1986,6 @@ pub fn a_or_an(s: &str) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
/// Grammatical tool for displaying messages to end users in a nice form.
|
||||
///
|
||||
/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
|
||||
pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
|
||||
match v {
|
||||
[] => "".to_string(),
|
||||
[a] => a.to_string(),
|
||||
[a, b] => format!("{a} and {b}"),
|
||||
[a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||
pub enum TerminalUrl {
|
||||
No,
|
||||
|
|
|
|||
|
|
@ -616,7 +616,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_allowed_through_unstable_modules, Normal, template!(Word, NameValueStr: "deprecation message"),
|
||||
rustc_allowed_through_unstable_modules, Normal, template!(NameValueStr: "deprecation message"),
|
||||
WarnFollowing, EncodeCrossCrate::No,
|
||||
"rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
|
||||
through unstable paths"
|
||||
|
|
|
|||
|
|
@ -234,6 +234,9 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a
|
|||
.help = consider moving this inherent impl into the crate defining the type if possible
|
||||
.span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
|
||||
|
||||
hir_analysis_invalid_base_type = `{$ty}` is not a valid base type for range patterns
|
||||
.note = range patterns only support integers
|
||||
|
||||
hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}`
|
||||
.note = type of `self` must not be a method generic parameter type
|
||||
|
||||
|
|
@ -438,7 +441,6 @@ hir_analysis_pattern_type_wild_pat = wildcard patterns are not permitted for pat
|
|||
.label = this type is the same as the inner type without a pattern
|
||||
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
|
||||
.label = not allowed in type signatures
|
||||
|
||||
hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
|
||||
.label = `Self` is not a generic argument, but an alias to the type of the {$what}
|
||||
|
||||
|
|
|
|||
|
|
@ -778,13 +778,13 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Static { .. } => {
|
||||
tcx.ensure().typeck(def_id);
|
||||
tcx.ensure_ok().typeck(def_id);
|
||||
maybe_check_static_with_link_section(tcx, def_id);
|
||||
check_static_inhabited(tcx, def_id);
|
||||
check_static_linkage(tcx, def_id);
|
||||
}
|
||||
DefKind::Const => {
|
||||
tcx.ensure().typeck(def_id);
|
||||
tcx.ensure_ok().typeck(def_id);
|
||||
}
|
||||
DefKind::Enum => {
|
||||
check_enum(tcx, def_id);
|
||||
|
|
@ -804,7 +804,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
DefKind::Impl { of_trait } => {
|
||||
if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) {
|
||||
if tcx
|
||||
.ensure()
|
||||
.ensure_ok()
|
||||
.coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id)
|
||||
.is_ok()
|
||||
{
|
||||
|
|
@ -1042,7 +1042,7 @@ fn check_impl_items_against_trait<'tcx>(
|
|||
continue;
|
||||
};
|
||||
|
||||
let res = tcx.ensure().compare_impl_item(impl_item.expect_local());
|
||||
let res = tcx.ensure_ok().compare_impl_item(impl_item.expect_local());
|
||||
|
||||
if res.is_ok() {
|
||||
match ty_impl_item.kind {
|
||||
|
|
@ -1488,7 +1488,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
|
||||
for v in def.variants() {
|
||||
if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {
|
||||
tcx.ensure().typeck(discr_def_id.expect_local());
|
||||
tcx.ensure_ok().typeck(discr_def_id.expect_local());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2034,7 +2034,7 @@ pub(super) fn check_type_bounds<'tcx>(
|
|||
) -> Result<(), ErrorGuaranteed> {
|
||||
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
|
||||
// other `Foo` impls are incoherent.
|
||||
tcx.ensure().coherent_trait(impl_trait_ref.def_id)?;
|
||||
tcx.ensure_ok().coherent_trait(impl_trait_ref.def_id)?;
|
||||
|
||||
let param_env = tcx.param_env(impl_ty.def_id);
|
||||
debug!(?param_env);
|
||||
|
|
|
|||
|
|
@ -1046,7 +1046,7 @@ fn check_associated_item(
|
|||
|
||||
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
|
||||
// other `Foo` impls are incoherent.
|
||||
tcx.ensure()
|
||||
tcx.ensure_ok()
|
||||
.coherent_trait(tcx.parent(item.trait_item_def_id.unwrap_or(item_id.into())))?;
|
||||
|
||||
let self_ty = match item.container {
|
||||
|
|
@ -1354,7 +1354,7 @@ fn check_impl<'tcx>(
|
|||
let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().instantiate_identity();
|
||||
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
|
||||
// other `Foo` impls are incoherent.
|
||||
tcx.ensure().coherent_trait(trait_ref.def_id)?;
|
||||
tcx.ensure_ok().coherent_trait(trait_ref.def_id)?;
|
||||
let trait_span = hir_trait_ref.path.span;
|
||||
let trait_ref = wfcx.normalize(
|
||||
trait_span,
|
||||
|
|
@ -2268,11 +2268,13 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> {
|
||||
let items = tcx.hir_module_items(module);
|
||||
let res = items
|
||||
.par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))
|
||||
.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)))
|
||||
.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)))
|
||||
.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)))
|
||||
.and(items.par_opaques(|item| tcx.ensure().check_well_formed(item)));
|
||||
.par_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))
|
||||
.and(items.par_impl_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)))
|
||||
.and(items.par_trait_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)))
|
||||
.and(
|
||||
items.par_foreign_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)),
|
||||
)
|
||||
.and(items.par_opaques(|item| tcx.ensure_ok().check_well_formed(item)));
|
||||
if module == LocalModDefId::CRATE_DEF_ID {
|
||||
super::entry::check_for_entry_fn(tcx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E
|
|||
// errors; other parts of the code may demand it for the info of
|
||||
// course.
|
||||
let span = tcx.def_span(impl_did);
|
||||
tcx.at(span).ensure().coerce_unsized_info(impl_did)
|
||||
tcx.at(span).ensure_ok().coerce_unsized_info(impl_did)
|
||||
}
|
||||
|
||||
fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
|
|||
let Some(impls) = tcx.all_local_trait_impls(()).get(&def_id) else { return Ok(()) };
|
||||
// Trigger building the specialization graph for the trait. This will detect and report any
|
||||
// overlap errors.
|
||||
let mut res = tcx.ensure().specialization_graph_of(def_id);
|
||||
let mut res = tcx.ensure_ok().specialization_graph_of(def_id);
|
||||
|
||||
for &impl_def_id in impls {
|
||||
let trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
|
||||
|
|
@ -162,7 +162,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
|
|||
.and(check_impl(tcx, impl_def_id, trait_ref, trait_def))
|
||||
.and(check_object_overlap(tcx, impl_def_id, trait_ref))
|
||||
.and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def))
|
||||
.and(tcx.ensure().orphan_check_impl(impl_def_id))
|
||||
.and(tcx.ensure_ok().orphan_check_impl(impl_def_id))
|
||||
.and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -292,16 +292,16 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
|
|||
match param.kind {
|
||||
hir::GenericParamKind::Lifetime { .. } => {}
|
||||
hir::GenericParamKind::Type { default: Some(_), .. } => {
|
||||
self.tcx.ensure().type_of(param.def_id);
|
||||
self.tcx.ensure_ok().type_of(param.def_id);
|
||||
}
|
||||
hir::GenericParamKind::Type { .. } => {}
|
||||
hir::GenericParamKind::Const { default, .. } => {
|
||||
self.tcx.ensure().type_of(param.def_id);
|
||||
self.tcx.ensure_ok().type_of(param.def_id);
|
||||
if let Some(default) = default {
|
||||
// need to store default and type of default
|
||||
self.tcx.ensure().const_param_default(param.def_id);
|
||||
self.tcx.ensure_ok().const_param_default(param.def_id);
|
||||
if let hir::ConstArgKind::Anon(ac) = default.kind {
|
||||
self.tcx.ensure().type_of(ac.def_id);
|
||||
self.tcx.ensure_ok().type_of(ac.def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -312,8 +312,8 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
|
|||
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
if let hir::ExprKind::Closure(closure) = expr.kind {
|
||||
self.tcx.ensure().generics_of(closure.def_id);
|
||||
self.tcx.ensure().codegen_fn_attrs(closure.def_id);
|
||||
self.tcx.ensure_ok().generics_of(closure.def_id);
|
||||
self.tcx.ensure_ok().codegen_fn_attrs(closure.def_id);
|
||||
// We do not call `type_of` for closures here as that
|
||||
// depends on typecheck and would therefore hide
|
||||
// any further errors in case one typeck fails.
|
||||
|
|
@ -325,15 +325,15 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
|
|||
/// `check_item_type` ensures that it's called instead.
|
||||
fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) {
|
||||
let def_id = opaque.def_id;
|
||||
self.tcx.ensure().generics_of(def_id);
|
||||
self.tcx.ensure().predicates_of(def_id);
|
||||
self.tcx.ensure().explicit_item_bounds(def_id);
|
||||
self.tcx.ensure().explicit_item_self_bounds(def_id);
|
||||
self.tcx.ensure().item_bounds(def_id);
|
||||
self.tcx.ensure().item_self_bounds(def_id);
|
||||
self.tcx.ensure_ok().generics_of(def_id);
|
||||
self.tcx.ensure_ok().predicates_of(def_id);
|
||||
self.tcx.ensure_ok().explicit_item_bounds(def_id);
|
||||
self.tcx.ensure_ok().explicit_item_self_bounds(def_id);
|
||||
self.tcx.ensure_ok().item_bounds(def_id);
|
||||
self.tcx.ensure_ok().item_self_bounds(def_id);
|
||||
if self.tcx.is_conditionally_const(def_id) {
|
||||
self.tcx.ensure().explicit_implied_const_bounds(def_id);
|
||||
self.tcx.ensure().const_conditions(def_id);
|
||||
self.tcx.ensure_ok().explicit_implied_const_bounds(def_id);
|
||||
self.tcx.ensure_ok().const_conditions(def_id);
|
||||
}
|
||||
intravisit::walk_opaque_ty(self, opaque);
|
||||
}
|
||||
|
|
@ -683,20 +683,20 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
hir::ItemKind::ForeignMod { items, .. } => {
|
||||
for item in *items {
|
||||
let item = tcx.hir().foreign_item(item.id);
|
||||
tcx.ensure().generics_of(item.owner_id);
|
||||
tcx.ensure().type_of(item.owner_id);
|
||||
tcx.ensure().predicates_of(item.owner_id);
|
||||
tcx.ensure_ok().generics_of(item.owner_id);
|
||||
tcx.ensure_ok().type_of(item.owner_id);
|
||||
tcx.ensure_ok().predicates_of(item.owner_id);
|
||||
if tcx.is_conditionally_const(def_id) {
|
||||
tcx.ensure().explicit_implied_const_bounds(def_id);
|
||||
tcx.ensure().const_conditions(def_id);
|
||||
tcx.ensure_ok().explicit_implied_const_bounds(def_id);
|
||||
tcx.ensure_ok().const_conditions(def_id);
|
||||
}
|
||||
match item.kind {
|
||||
hir::ForeignItemKind::Fn(..) => {
|
||||
tcx.ensure().codegen_fn_attrs(item.owner_id);
|
||||
tcx.ensure().fn_sig(item.owner_id)
|
||||
tcx.ensure_ok().codegen_fn_attrs(item.owner_id);
|
||||
tcx.ensure_ok().fn_sig(item.owner_id)
|
||||
}
|
||||
hir::ForeignItemKind::Static(..) => {
|
||||
tcx.ensure().codegen_fn_attrs(item.owner_id);
|
||||
tcx.ensure_ok().codegen_fn_attrs(item.owner_id);
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
visitor.visit_foreign_item(item);
|
||||
placeholder_type_error(
|
||||
|
|
@ -713,40 +713,40 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
}
|
||||
}
|
||||
hir::ItemKind::Enum(..) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
lower_enum_variant_types(tcx, def_id.to_def_id());
|
||||
}
|
||||
hir::ItemKind::Impl { .. } => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().impl_trait_header(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure().associated_items(def_id);
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().impl_trait_header(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
tcx.ensure_ok().associated_items(def_id);
|
||||
}
|
||||
hir::ItemKind::Trait(..) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().trait_def(def_id);
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().trait_def(def_id);
|
||||
tcx.at(it.span).explicit_super_predicates_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure().associated_items(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
tcx.ensure_ok().associated_items(def_id);
|
||||
}
|
||||
hir::ItemKind::TraitAlias(..) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.at(it.span).explicit_implied_predicates_of(def_id);
|
||||
tcx.at(it.span).explicit_super_predicates_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
}
|
||||
hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
|
||||
for f in struct_def.fields() {
|
||||
tcx.ensure().generics_of(f.def_id);
|
||||
tcx.ensure().type_of(f.def_id);
|
||||
tcx.ensure().predicates_of(f.def_id);
|
||||
tcx.ensure_ok().generics_of(f.def_id);
|
||||
tcx.ensure_ok().type_of(f.def_id);
|
||||
tcx.ensure_ok().predicates_of(f.def_id);
|
||||
}
|
||||
|
||||
if let Some(ctor_def_id) = struct_def.ctor_def_id() {
|
||||
|
|
@ -755,15 +755,15 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
}
|
||||
|
||||
hir::ItemKind::TyAlias(..) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
}
|
||||
|
||||
hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
if !ty.is_suggestable_infer_ty() {
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
visitor.visit_item(it);
|
||||
|
|
@ -779,11 +779,11 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
}
|
||||
|
||||
hir::ItemKind::Fn { .. } => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure().fn_sig(def_id);
|
||||
tcx.ensure().codegen_fn_attrs(def_id);
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
tcx.ensure_ok().fn_sig(def_id);
|
||||
tcx.ensure_ok().codegen_fn_attrs(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -791,18 +791,18 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
|
||||
let trait_item = tcx.hir().trait_item(trait_item_id);
|
||||
let def_id = trait_item_id.owner_id;
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
let icx = ItemCtxt::new(tcx, def_id.def_id);
|
||||
|
||||
match trait_item.kind {
|
||||
hir::TraitItemKind::Fn(..) => {
|
||||
tcx.ensure().codegen_fn_attrs(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().fn_sig(def_id);
|
||||
tcx.ensure_ok().codegen_fn_attrs(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().fn_sig(def_id);
|
||||
}
|
||||
|
||||
hir::TraitItemKind::Const(ty, body_id) => {
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
|
||||
&& !(ty.is_suggestable_infer_ty() && body_id.is_some())
|
||||
{
|
||||
|
|
@ -821,9 +821,9 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
|
|||
}
|
||||
|
||||
hir::TraitItemKind::Type(_, Some(_)) => {
|
||||
tcx.ensure().item_bounds(def_id);
|
||||
tcx.ensure().item_self_bounds(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure_ok().item_bounds(def_id);
|
||||
tcx.ensure_ok().item_self_bounds(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
// Account for `type T = _;`.
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
visitor.visit_trait_item(trait_item);
|
||||
|
|
@ -838,8 +838,8 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
|
|||
}
|
||||
|
||||
hir::TraitItemKind::Type(_, None) => {
|
||||
tcx.ensure().item_bounds(def_id);
|
||||
tcx.ensure().item_self_bounds(def_id);
|
||||
tcx.ensure_ok().item_bounds(def_id);
|
||||
tcx.ensure_ok().item_self_bounds(def_id);
|
||||
// #74612: Visit and try to find bad placeholders
|
||||
// even if there is no concrete type.
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
|
|
@ -856,20 +856,20 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
|
|||
}
|
||||
};
|
||||
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
}
|
||||
|
||||
fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
|
||||
let def_id = impl_item_id.owner_id;
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
let impl_item = tcx.hir().impl_item(impl_item_id);
|
||||
let icx = ItemCtxt::new(tcx, def_id.def_id);
|
||||
match impl_item.kind {
|
||||
hir::ImplItemKind::Fn(..) => {
|
||||
tcx.ensure().codegen_fn_attrs(def_id);
|
||||
tcx.ensure().fn_sig(def_id);
|
||||
tcx.ensure_ok().codegen_fn_attrs(def_id);
|
||||
tcx.ensure_ok().fn_sig(def_id);
|
||||
}
|
||||
hir::ImplItemKind::Type(_) => {
|
||||
// Account for `type T = _;`
|
||||
|
|
@ -904,9 +904,9 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
|
|||
}
|
||||
|
||||
fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
}
|
||||
|
||||
fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||
|
|
@ -937,9 +937,9 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
|
|||
);
|
||||
|
||||
for f in &variant.fields {
|
||||
tcx.ensure().generics_of(f.did);
|
||||
tcx.ensure().type_of(f.did);
|
||||
tcx.ensure().predicates_of(f.did);
|
||||
tcx.ensure_ok().generics_of(f.did);
|
||||
tcx.ensure_ok().type_of(f.did);
|
||||
tcx.ensure_ok().predicates_of(f.did);
|
||||
}
|
||||
|
||||
// Lower the ctor, if any. This also registers the variant as an item.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_macros::Diagnostic;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -7,3 +8,14 @@ pub(crate) struct WildPatTy {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_invalid_base_type)]
|
||||
pub(crate) struct InvalidBaseType<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
#[primary_span]
|
||||
pub ty_span: Span,
|
||||
pub pat: &'static str,
|
||||
#[note]
|
||||
pub pat_span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rustc_data_structures::sorted_map::SortedMap;
|
|||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err,
|
||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
|
@ -808,14 +808,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.map(|(trait_, mut assocs)| {
|
||||
assocs.sort();
|
||||
let trait_ = trait_.print_trait_sugared();
|
||||
format!("{} in `{trait_}`", match &assocs[..] {
|
||||
[] => String::new(),
|
||||
[only] => format!("`{only}`"),
|
||||
[assocs @ .., last] => format!(
|
||||
"{} and `{last}`",
|
||||
assocs.iter().map(|a| format!("`{a}`")).collect::<Vec<_>>().join(", ")
|
||||
),
|
||||
})
|
||||
format!(
|
||||
"{} in `{trait_}`",
|
||||
listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default()
|
||||
)
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
names.sort();
|
||||
|
|
@ -1075,18 +1071,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
})
|
||||
.collect();
|
||||
let this_type = match &types_and_spans[..] {
|
||||
[.., _, (last, _)] => format!(
|
||||
"{} and {last}",
|
||||
types_and_spans[..types_and_spans.len() - 1]
|
||||
.iter()
|
||||
.map(|(x, _)| x.as_str())
|
||||
.intersperse(", ")
|
||||
.collect::<String>()
|
||||
),
|
||||
[(only, _)] => only.to_string(),
|
||||
[] => bug!("expected one segment to deny"),
|
||||
};
|
||||
let this_type = listify(&types_and_spans, |(t, _)| t.to_string())
|
||||
.expect("expected one segment to deny");
|
||||
|
||||
let arg_spans: Vec<Span> = segments
|
||||
.clone()
|
||||
|
|
@ -1102,21 +1088,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
ProhibitGenericsArg::Infer => kinds.push("generic"),
|
||||
});
|
||||
|
||||
let (kind, s) = match kinds[..] {
|
||||
[.., _, last] => (
|
||||
format!(
|
||||
"{} and {last}",
|
||||
kinds[..kinds.len() - 1]
|
||||
.iter()
|
||||
.map(|&x| x)
|
||||
.intersperse(", ")
|
||||
.collect::<String>()
|
||||
),
|
||||
"s",
|
||||
),
|
||||
[only] => (only.to_string(), ""),
|
||||
[] => bug!("expected at least one generic to prohibit"),
|
||||
};
|
||||
let s = pluralize!(kinds.len());
|
||||
let kind =
|
||||
listify(&kinds, |k| k.to_string()).expect("expected at least one generic to prohibit");
|
||||
let last_span = *arg_spans.last().unwrap();
|
||||
let span: MultiSpan = arg_spans.into();
|
||||
let mut err = struct_span_code_err!(
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ use tracing::{debug, instrument};
|
|||
|
||||
use crate::bounds::Bounds;
|
||||
use crate::check::check_abi_fn_ptr;
|
||||
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy};
|
||||
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, WildPatTy};
|
||||
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
|
||||
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
|
||||
use crate::middle::resolve_bound_vars as rbv;
|
||||
|
|
@ -2432,6 +2432,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self.ty_infer(None, hir_ty.span)
|
||||
}
|
||||
hir::TyKind::Pat(ty, pat) => {
|
||||
let ty_span = ty.span;
|
||||
let ty = self.lower_ty(ty);
|
||||
let pat_ty = match pat.kind {
|
||||
hir::PatKind::Wild => {
|
||||
|
|
@ -2439,6 +2440,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
Ty::new_error(tcx, err)
|
||||
}
|
||||
hir::PatKind::Range(start, end, include_end) => {
|
||||
let ty = match ty.kind() {
|
||||
ty::Int(_) | ty::Uint(_) | ty::Char => ty,
|
||||
_ => Ty::new_error(
|
||||
tcx,
|
||||
self.dcx().emit_err(InvalidBaseType {
|
||||
ty,
|
||||
pat: "range",
|
||||
ty_span,
|
||||
pat_span: pat.span,
|
||||
}),
|
||||
),
|
||||
};
|
||||
let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> {
|
||||
let (c, c_ty) = match expr.kind {
|
||||
hir::PatExprKind::Lit { lit, negated } => {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ pub(crate) fn check_impl_wf(
|
|||
// Check that the args are constrained. We queryfied the check for ty/const params
|
||||
// since unconstrained type/const params cause ICEs in projection, so we want to
|
||||
// detect those specifically and project those to `TyKind::Error`.
|
||||
let mut res = tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
|
||||
let mut res = tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
|
||||
res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id));
|
||||
|
||||
if tcx.features().min_specialization() {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ use rustc_middle::middle;
|
|||
use rustc_middle::mir::interpret::GlobalId;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
pub use crate::collect::suggest_impl_trait;
|
||||
|
|
@ -139,16 +139,20 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||
let _prof_timer = tcx.sess.timer("type_check_crate");
|
||||
|
||||
tcx.sess.time("coherence_checking", || {
|
||||
// When discarding query call results, use an explicit type to indicate
|
||||
// what we are intending to discard, to help future type-based refactoring.
|
||||
type R = Result<(), ErrorGuaranteed>;
|
||||
|
||||
tcx.hir().par_for_each_module(|module| {
|
||||
let _ = tcx.ensure().check_mod_type_wf(module);
|
||||
let _: R = tcx.ensure_ok().check_mod_type_wf(module);
|
||||
});
|
||||
|
||||
for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
|
||||
let _ = tcx.ensure().coherent_trait(trait_def_id);
|
||||
let _: R = tcx.ensure_ok().coherent_trait(trait_def_id);
|
||||
}
|
||||
// these queries are executed for side-effects (error reporting):
|
||||
let _ = tcx.ensure().crate_inherent_impls_validity_check(());
|
||||
let _ = tcx.ensure().crate_inherent_impls_overlap_check(());
|
||||
let _: R = tcx.ensure_ok().crate_inherent_impls_validity_check(());
|
||||
let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(());
|
||||
});
|
||||
|
||||
if tcx.features().rustc_attrs() {
|
||||
|
|
@ -167,12 +171,12 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||
tcx.hir().par_body_owners(|item_def_id| {
|
||||
let def_kind = tcx.def_kind(item_def_id);
|
||||
match def_kind {
|
||||
DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id),
|
||||
DefKind::Static { .. } => tcx.ensure_ok().eval_static_initializer(item_def_id),
|
||||
DefKind::Const if tcx.generics_of(item_def_id).is_empty() => {
|
||||
let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty());
|
||||
let cid = GlobalId { instance, promoted: None };
|
||||
let typing_env = ty::TypingEnv::fully_monomorphized();
|
||||
tcx.ensure().eval_to_const_value_raw(typing_env.as_query_input(cid));
|
||||
tcx.ensure_ok().eval_to_const_value_raw(typing_env.as_query_input(cid));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
@ -185,11 +189,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||
tcx.hir().par_body_owners(|item_def_id| {
|
||||
let def_kind = tcx.def_kind(item_def_id);
|
||||
if !matches!(def_kind, DefKind::AnonConst) {
|
||||
tcx.ensure().typeck(item_def_id);
|
||||
tcx.ensure_ok().typeck(item_def_id);
|
||||
}
|
||||
});
|
||||
|
||||
tcx.ensure().check_unused_traits(());
|
||||
tcx.ensure_ok().check_unused_traits(());
|
||||
}
|
||||
|
||||
/// Lower a [`hir::Ty`] to a [`Ty`].
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ pub(crate) fn check_legal_trait_for_method_call(
|
|||
};
|
||||
return Err(tcx.dcx().emit_err(errors::ExplicitDestructorCall { span, sugg }));
|
||||
}
|
||||
tcx.ensure().coherent_trait(trait_id)
|
||||
tcx.ensure_ok().coherent_trait(trait_id)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ use rustc_infer::traits::{
|
|||
IfExpressionCause, MatchExpressionArmCause, Obligation, PredicateObligation,
|
||||
PredicateObligations,
|
||||
};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::traits::BuiltinImplSource;
|
||||
use rustc_middle::ty::adjustment::{
|
||||
|
|
@ -1937,7 +1936,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
cond_expr.span.desugaring_kind(),
|
||||
None | Some(DesugaringKind::WhileLoop)
|
||||
)
|
||||
&& !in_external_macro(fcx.tcx.sess, cond_expr.span)
|
||||
&& !cond_expr.span.in_external_macro(fcx.tcx.sess.source_map())
|
||||
&& !matches!(
|
||||
cond_expr.kind,
|
||||
hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_errors::{Applicability, Diag, MultiSpan};
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan, listify};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
@ -1016,18 +1016,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
},
|
||||
self.tcx.def_path_str(candidate.item.container_id(self.tcx))
|
||||
),
|
||||
[.., last] if other_methods_in_scope.len() < 5 => {
|
||||
_ if other_methods_in_scope.len() < 5 => {
|
||||
format!(
|
||||
"the methods of the same name on {} and `{}`",
|
||||
other_methods_in_scope[..other_methods_in_scope.len() - 1]
|
||||
.iter()
|
||||
.map(|c| format!(
|
||||
"`{}`",
|
||||
self.tcx.def_path_str(c.item.container_id(self.tcx))
|
||||
))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
self.tcx.def_path_str(last.item.container_id(self.tcx))
|
||||
"the methods of the same name on {}",
|
||||
listify(
|
||||
&other_methods_in_scope[..other_methods_in_scope.len() - 1],
|
||||
|c| format!("`{}`", self.tcx.def_path_str(c.item.container_id(self.tcx)))
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
_ => format!(
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
|||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, pluralize,
|
||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, listify, pluralize,
|
||||
struct_span_code_err,
|
||||
};
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
|
|
@ -1658,8 +1658,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
hir_ty: Option<&'tcx hir::Ty<'tcx>>,
|
||||
expected: Expectation<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
self.dcx().span_err(inner_expr.span, "unsafe binder casts are not fully implemented");
|
||||
|
||||
match kind {
|
||||
hir::UnsafeBinderCastKind::Wrap => {
|
||||
let ascribed_ty =
|
||||
|
|
@ -2190,13 +2188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
if !missing_mandatory_fields.is_empty() {
|
||||
let s = pluralize!(missing_mandatory_fields.len());
|
||||
let fields: Vec<_> =
|
||||
missing_mandatory_fields.iter().map(|f| format!("`{f}`")).collect();
|
||||
let fields = match &fields[..] {
|
||||
[] => unreachable!(),
|
||||
[only] => only.to_string(),
|
||||
[start @ .., last] => format!("{} and {last}", start.join(", ")),
|
||||
};
|
||||
let fields = listify(&missing_mandatory_fields, |f| format!("`{f}`")).unwrap();
|
||||
self.dcx()
|
||||
.struct_span_err(
|
||||
span.shrink_to_hi(),
|
||||
|
|
@ -2553,25 +2545,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.partition(|field| field.2);
|
||||
err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field");
|
||||
if !remaining_private_fields.is_empty() {
|
||||
let remaining_private_fields_len = remaining_private_fields.len();
|
||||
let names = match &remaining_private_fields
|
||||
.iter()
|
||||
.map(|(name, _, _)| name)
|
||||
.collect::<Vec<_>>()[..]
|
||||
{
|
||||
_ if remaining_private_fields_len > 6 => String::new(),
|
||||
[name] => format!("`{name}` "),
|
||||
[names @ .., last] => {
|
||||
let names = names.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
|
||||
format!("{} and `{last}` ", names.join(", "))
|
||||
}
|
||||
[] => bug!("expected at least one private field to report"),
|
||||
let names = if remaining_private_fields.len() > 6 {
|
||||
String::new()
|
||||
} else {
|
||||
format!(
|
||||
"{} ",
|
||||
listify(&remaining_private_fields, |(name, _, _)| format!("`{name}`"))
|
||||
.expect("expected at least one private field to report")
|
||||
)
|
||||
};
|
||||
err.note(format!(
|
||||
"{}private field{s} {names}that {were} not provided",
|
||||
if used_fields.is_empty() { "" } else { "...and other " },
|
||||
s = pluralize!(remaining_private_fields_len),
|
||||
were = pluralize!("was", remaining_private_fields_len),
|
||||
s = pluralize!(remaining_private_fields.len()),
|
||||
were = pluralize!("was", remaining_private_fields.len()),
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ use itertools::Itertools;
|
|||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an,
|
||||
display_list_with_comma_and, pluralize,
|
||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, listify, pluralize,
|
||||
};
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
|
@ -2462,7 +2461,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
param.span,
|
||||
format!(
|
||||
"{} need{} to match the {} type of this parameter",
|
||||
display_list_with_comma_and(&other_param_matched_names),
|
||||
listify(&other_param_matched_names, |n| n.to_string())
|
||||
.unwrap_or_default(),
|
||||
pluralize!(if other_param_matched_names.len() == 1 {
|
||||
0
|
||||
} else {
|
||||
|
|
@ -2477,7 +2477,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
format!(
|
||||
"this parameter needs to match the {} type of {}",
|
||||
matched_ty,
|
||||
display_list_with_comma_and(&other_param_matched_names),
|
||||
listify(&other_param_matched_names, |n| n.to_string())
|
||||
.unwrap_or_default(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -2523,7 +2524,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
generic_param.span,
|
||||
format!(
|
||||
"{} {} reference this parameter `{}`",
|
||||
display_list_with_comma_and(¶m_idents_matching),
|
||||
listify(¶m_idents_matching, |n| n.to_string())
|
||||
.unwrap_or_default(),
|
||||
if param_idents_matching.len() == 2 { "both" } else { "all" },
|
||||
generic_param.name.ident().name,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use core::iter;
|
|||
use hir::def_id::LocalDefId;
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan};
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan, listify};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{
|
||||
|
|
@ -14,7 +14,6 @@ use rustc_hir::{
|
|||
};
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_hir_analysis::suggest_impl_trait;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
|
|
@ -770,7 +769,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// If the expression is from an external macro, then do not suggest
|
||||
// adding a semicolon, because there's nowhere to put it.
|
||||
// See issue #81943.
|
||||
&& !in_external_macro(self.tcx.sess, expression.span) =>
|
||||
&& !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
|
||||
{
|
||||
if needs_block {
|
||||
err.multipart_suggestion(
|
||||
|
|
@ -1836,16 +1835,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
error.obligation.predicate,
|
||||
));
|
||||
}
|
||||
[errors @ .., last] => {
|
||||
_ => {
|
||||
diag.help(format!(
|
||||
"`Clone` is not implemented because the following trait bounds \
|
||||
could not be satisfied: {} and `{}`",
|
||||
errors
|
||||
.iter()
|
||||
.map(|e| format!("`{}`", e.obligation.predicate))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
last.obligation.predicate,
|
||||
could not be satisfied: {}",
|
||||
listify(&errors, |e| format!("`{}`", e.obligation.predicate))
|
||||
.unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -2265,7 +2260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected: Ty<'tcx>,
|
||||
expr_ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
if in_external_macro(self.tcx.sess, expr.span) {
|
||||
if expr.span.in_external_macro(self.tcx.sess.source_map()) {
|
||||
return false;
|
||||
}
|
||||
if let ty::Adt(expected_adt, args) = expected.kind() {
|
||||
|
|
@ -2593,14 +2588,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
)> {
|
||||
let sess = self.sess();
|
||||
let sp = expr.span;
|
||||
let sm = sess.source_map();
|
||||
|
||||
// If the span is from an external macro, there's no suggestion we can make.
|
||||
if in_external_macro(sess, sp) {
|
||||
if sp.in_external_macro(sm) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let sm = sess.source_map();
|
||||
|
||||
let replace_prefix = |s: &str, old: &str, new: &str| {
|
||||
s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
use core::ops::ControlFlow;
|
||||
use std::borrow::Cow;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use hir::Expr;
|
||||
use rustc_ast::ast::Mutability;
|
||||
|
|
@ -362,14 +363,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> {
|
||||
let mut file = None;
|
||||
let ty_str = self.tcx.short_ty_string(rcvr_ty, &mut file);
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
rcvr_expr.span,
|
||||
E0599,
|
||||
"cannot write into `{}`",
|
||||
ty_str
|
||||
self.tcx.short_string(rcvr_ty, &mut file),
|
||||
);
|
||||
*err.long_ty_path() = file;
|
||||
err.span_note(
|
||||
rcvr_expr.span,
|
||||
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
|
||||
|
|
@ -380,11 +381,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
"a writer is needed before this format string",
|
||||
);
|
||||
};
|
||||
if let Some(file) = file {
|
||||
err.note(format!("the full type name has been written to '{}'", file.display()));
|
||||
err.note("consider using `--verbose` to print the full type name to the console");
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
|
|
@ -595,7 +591,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
(predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string()))
|
||||
} else {
|
||||
(
|
||||
tcx.short_ty_string(rcvr_ty, &mut ty_file),
|
||||
tcx.short_string(rcvr_ty, &mut ty_file),
|
||||
with_forced_trimmed_paths!(rcvr_ty.to_string()),
|
||||
)
|
||||
};
|
||||
|
|
@ -624,6 +620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
span,
|
||||
item_name,
|
||||
&short_ty_str,
|
||||
&mut ty_file,
|
||||
) {
|
||||
return guar;
|
||||
}
|
||||
|
|
@ -635,6 +632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
item_kind,
|
||||
item_name,
|
||||
&short_ty_str,
|
||||
&mut ty_file,
|
||||
) {
|
||||
return guar;
|
||||
}
|
||||
|
|
@ -728,10 +726,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ty_str = short_ty_str;
|
||||
}
|
||||
|
||||
if let Some(file) = ty_file {
|
||||
err.note(format!("the full type name has been written to '{}'", file.display(),));
|
||||
err.note("consider using `--verbose` to print the full type name to the console");
|
||||
}
|
||||
if rcvr_ty.references_error() {
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
|
|
@ -1314,7 +1308,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
|
||||
let actual_prefix = rcvr_ty.prefix_string(self.tcx);
|
||||
info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
|
||||
let mut long_ty_file = None;
|
||||
let (primary_message, label, notes) = if unimplemented_traits.len() == 1
|
||||
&& unimplemented_traits_only
|
||||
{
|
||||
|
|
@ -1329,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
let OnUnimplementedNote { message, label, notes, .. } = self
|
||||
.err_ctxt()
|
||||
.on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file);
|
||||
.on_unimplemented_note(trait_ref, &obligation, &mut ty_file);
|
||||
(message, label, notes)
|
||||
})
|
||||
.unwrap()
|
||||
|
|
@ -1343,15 +1336,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
)
|
||||
});
|
||||
err.primary_message(primary_message);
|
||||
if let Some(file) = long_ty_file {
|
||||
err.note(format!(
|
||||
"the full name for the type has been written to '{}'",
|
||||
file.display(),
|
||||
));
|
||||
err.note(
|
||||
"consider using `--verbose` to print the full type name to the console",
|
||||
);
|
||||
}
|
||||
if let Some(label) = label {
|
||||
custom_span_label = true;
|
||||
err.span_label(span, label);
|
||||
|
|
@ -2403,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
span: Span,
|
||||
item_name: Ident,
|
||||
ty_str: &str,
|
||||
long_ty_path: &mut Option<PathBuf>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
if let SelfSource::MethodCall(expr) = source {
|
||||
for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
|
||||
|
|
@ -2460,7 +2445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
if pick.is_ok() {
|
||||
let range_span = parent_expr.span.with_hi(expr.span.hi());
|
||||
return Err(self.dcx().emit_err(errors::MissingParenthesesInRange {
|
||||
let mut err = self.dcx().create_err(errors::MissingParenthesesInRange {
|
||||
span,
|
||||
ty_str: ty_str.to_string(),
|
||||
method_name: item_name.as_str().to_string(),
|
||||
|
|
@ -2469,7 +2454,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
left: range_span.shrink_to_lo(),
|
||||
right: range_span.shrink_to_hi(),
|
||||
}),
|
||||
}));
|
||||
});
|
||||
*err.long_ty_path() = long_ty_path.take();
|
||||
return Err(err.emit());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2486,6 +2473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
item_kind: &str,
|
||||
item_name: Ident,
|
||||
ty_str: &str,
|
||||
long_ty_path: &mut Option<PathBuf>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let found_candidate = all_traits(self.tcx)
|
||||
.into_iter()
|
||||
|
|
@ -2526,6 +2514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
item_name,
|
||||
ty_str
|
||||
);
|
||||
*err.long_ty_path() = long_ty_path.take();
|
||||
let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
|
||||
match expr.kind {
|
||||
ExprKind::Lit(lit) => {
|
||||
|
|
|
|||
|
|
@ -804,7 +804,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Determine the binding mode...
|
||||
let bm = match user_bind_annot {
|
||||
BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
|
||||
BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => {
|
||||
// Only mention the experimental `mut_ref` feature if if we're in edition 2024 and
|
||||
// using other experimental matching features compatible with it.
|
||||
if pat.span.at_least_rust_2024()
|
||||
|
|
@ -826,22 +826,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// `mut` resets the binding mode on edition <= 2021
|
||||
self.add_rust_2024_migration_desugared_pat(
|
||||
pat_info.top_info.hir_id,
|
||||
pat.span,
|
||||
pat,
|
||||
ident.span,
|
||||
"requires binding by-value, but the implicit default is by-reference",
|
||||
def_br_mutbl,
|
||||
);
|
||||
BindingMode(ByRef::No, Mutability::Mut)
|
||||
}
|
||||
}
|
||||
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
|
||||
BindingMode(ByRef::Yes(_), _) => {
|
||||
if matches!(def_br, ByRef::Yes(_)) {
|
||||
if let ByRef::Yes(def_br_mutbl) = def_br {
|
||||
// `ref`/`ref mut` overrides the binding mode on edition <= 2021
|
||||
self.add_rust_2024_migration_desugared_pat(
|
||||
pat_info.top_info.hir_id,
|
||||
pat.span,
|
||||
pat,
|
||||
ident.span,
|
||||
"cannot override to bind by-reference when that is the implicit default",
|
||||
def_br_mutbl,
|
||||
);
|
||||
}
|
||||
user_bind_annot
|
||||
|
|
@ -2378,9 +2378,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pat_info.binding_mode = ByRef::No;
|
||||
self.add_rust_2024_migration_desugared_pat(
|
||||
pat_info.top_info.hir_id,
|
||||
pat.span,
|
||||
pat,
|
||||
inner.span,
|
||||
"cannot implicitly match against multiple layers of reference",
|
||||
inh_mut,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2770,33 +2770,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fn add_rust_2024_migration_desugared_pat(
|
||||
&self,
|
||||
pat_id: HirId,
|
||||
subpat_span: Span,
|
||||
subpat: &'tcx Pat<'tcx>,
|
||||
cutoff_span: Span,
|
||||
detailed_label: &str,
|
||||
def_br_mutbl: Mutability,
|
||||
) {
|
||||
// Try to trim the span we're labeling to just the `&` or binding mode that's an issue.
|
||||
// If the subpattern's span is is from an expansion, the emitted label will not be trimmed.
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
let cutoff_span = source_map
|
||||
.span_extend_prev_while(cutoff_span, char::is_whitespace)
|
||||
.span_extend_prev_while(cutoff_span, |c| c.is_whitespace() || c == '(')
|
||||
.unwrap_or(cutoff_span);
|
||||
// Ensure we use the syntax context and thus edition of `subpat_span`; this will be a hard
|
||||
// Ensure we use the syntax context and thus edition of `subpat.span`; this will be a hard
|
||||
// error if the subpattern is of edition >= 2024.
|
||||
let trimmed_span = subpat_span.until(cutoff_span).with_ctxt(subpat_span.ctxt());
|
||||
let trimmed_span = subpat.span.until(cutoff_span).with_ctxt(subpat.span.ctxt());
|
||||
|
||||
let mut typeck_results = self.typeck_results.borrow_mut();
|
||||
let mut table = typeck_results.rust_2024_migration_desugared_pats_mut();
|
||||
// FIXME(ref_pat_eat_one_layer_2024): The migration diagnostic doesn't know how to track the
|
||||
// default binding mode in the presence of Rule 3 or Rule 5. As a consequence, the labels it
|
||||
// gives for default binding modes are wrong, as well as suggestions based on the default
|
||||
// binding mode. This keeps it from making those suggestions, as doing so could panic.
|
||||
let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
|
||||
primary_labels: Vec::new(),
|
||||
bad_modifiers: false,
|
||||
bad_ref_pats: false,
|
||||
suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
|
||||
&& !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
|
||||
});
|
||||
|
||||
// Only provide a detailed label if the problematic subpattern isn't from an expansion.
|
||||
// In the case that it's from a macro, we'll add a more detailed note in the emitter.
|
||||
let desc = if subpat_span.from_expansion() {
|
||||
"default binding mode is reset within expansion"
|
||||
let from_expansion = subpat.span.from_expansion();
|
||||
let primary_label = if from_expansion {
|
||||
// NB: This wording assumes the only expansions that can produce problematic reference
|
||||
// patterns and bindings are macros. If a desugaring or AST pass is added that can do
|
||||
// so, we may want to inspect the span's source callee or macro backtrace.
|
||||
"occurs within macro expansion".to_owned()
|
||||
} else {
|
||||
detailed_label
|
||||
let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
|
||||
info.bad_modifiers |= true;
|
||||
// If the user-provided binding modifier doesn't match the default binding mode, we'll
|
||||
// need to suggest reference patterns, which can affect other bindings.
|
||||
// For simplicity, we opt to suggest making the pattern fully explicit.
|
||||
info.suggest_eliding_modes &=
|
||||
user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
|
||||
"binding modifier"
|
||||
} else {
|
||||
info.bad_ref_pats |= true;
|
||||
// For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll
|
||||
// suggest adding them instead, which can affect the types assigned to bindings.
|
||||
// As such, we opt to suggest making the pattern fully explicit.
|
||||
info.suggest_eliding_modes = false;
|
||||
"reference pattern"
|
||||
};
|
||||
let dbm_str = match def_br_mutbl {
|
||||
Mutability::Not => "ref",
|
||||
Mutability::Mut => "ref mut",
|
||||
};
|
||||
format!("{pat_kind} not allowed under `{dbm_str}` default binding mode")
|
||||
};
|
||||
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.rust_2024_migration_desugared_pats_mut()
|
||||
.entry(pat_id)
|
||||
.or_default()
|
||||
.push((trimmed_span, desc.to_owned()));
|
||||
info.primary_labels.push((trimmed_span, primary_label));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ use rustc_macros::extension;
|
|||
pub use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::select;
|
||||
pub use rustc_middle::ty::IntVarValue;
|
||||
|
|
@ -46,6 +45,7 @@ use tracing::{debug, instrument};
|
|||
use type_variable::TypeVariableOrigin;
|
||||
|
||||
use crate::infer::region_constraints::UndoLog;
|
||||
use crate::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
|
||||
use crate::traits::{
|
||||
self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine,
|
||||
};
|
||||
|
|
@ -64,6 +64,7 @@ pub mod relate;
|
|||
pub mod resolve;
|
||||
pub(crate) mod snapshot;
|
||||
mod type_variable;
|
||||
mod unify_key;
|
||||
|
||||
/// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper
|
||||
/// around `PredicateObligations<'tcx>`, but it has one important property:
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ use rustc_data_structures::undo_log::UndoLogs;
|
|||
use rustc_data_structures::unify as ut;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_middle::infer::unify_key::{RegionVariableValue, RegionVidKey};
|
||||
use rustc_middle::ty::{self, ReBound, ReStatic, ReVar, Region, RegionVid, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use tracing::{debug, instrument};
|
||||
|
|
@ -17,6 +16,7 @@ use self::CombineMapType::*;
|
|||
use self::UndoLog::*;
|
||||
use super::{MiscVariable, RegionVariableOrigin, Rollback, SubregionOrigin};
|
||||
use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot};
|
||||
use crate::infer::unify_key::{RegionVariableValue, RegionVidKey};
|
||||
|
||||
mod leak_check;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ use rustc_data_structures::sso::SsoHashMap;
|
|||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::infer::unify_key::ConstVariableValue;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::visit::MaxUniverse;
|
||||
use rustc_middle::ty::{
|
||||
|
|
@ -18,6 +17,7 @@ use super::{
|
|||
PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
|
||||
};
|
||||
use crate::infer::type_variable::TypeVariableValue;
|
||||
use crate::infer::unify_key::ConstVariableValue;
|
||||
use crate::infer::{InferCtxt, RegionVariableOrigin, relate};
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use rustc_data_structures::{snapshot_vec as sv, unify as ut};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableValue, ConstVidKey};
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
|
||||
use rustc_type_ir::visit::TypeVisitableExt;
|
||||
|
|
@ -10,6 +9,7 @@ use ut::UnifyKey;
|
|||
|
||||
use super::VariableLengths;
|
||||
use crate::infer::type_variable::TypeVariableOrigin;
|
||||
use crate::infer::unify_key::{ConstVariableValue, ConstVidKey};
|
||||
use crate::infer::{ConstVariableOrigin, InferCtxt, RegionVariableOrigin, UnificationTable};
|
||||
|
||||
fn vars_since_snapshot<'tcx, T>(
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ use std::marker::PhantomData;
|
|||
|
||||
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
|
||||
use rustc_data_structures::{snapshot_vec as sv, unify as ut};
|
||||
use rustc_middle::infer::unify_key::{ConstVidKey, RegionVidKey};
|
||||
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::infer::unify_key::{ConstVidKey, RegionVidKey};
|
||||
use crate::infer::{InferCtxtInner, region_constraints, type_variable};
|
||||
use crate::traits;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,23 +2,18 @@ use std::cmp;
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::DefId;
|
||||
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
|
||||
pub trait ToType {
|
||||
fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum RegionVariableValue<'tcx> {
|
||||
pub(crate) enum RegionVariableValue<'tcx> {
|
||||
Known { value: ty::Region<'tcx> },
|
||||
Unknown { universe: ty::UniverseIndex },
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||
pub struct RegionVidKey<'tcx> {
|
||||
pub(crate) struct RegionVidKey<'tcx> {
|
||||
pub vid: ty::RegionVid,
|
||||
pub phantom: PhantomData<RegionVariableValue<'tcx>>,
|
||||
}
|
||||
|
|
@ -44,7 +39,8 @@ impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct RegionUnificationError;
|
||||
pub(crate) struct RegionUnificationError;
|
||||
|
||||
impl<'tcx> UnifyValue for RegionVariableValue<'tcx> {
|
||||
type Error = RegionUnificationError;
|
||||
|
||||
|
|
@ -100,7 +96,7 @@ pub struct ConstVariableOrigin {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ConstVariableValue<'tcx> {
|
||||
pub(crate) enum ConstVariableValue<'tcx> {
|
||||
Known { value: ty::Const<'tcx> },
|
||||
Unknown { origin: ConstVariableOrigin, universe: ty::UniverseIndex },
|
||||
}
|
||||
|
|
@ -108,7 +104,7 @@ pub enum ConstVariableValue<'tcx> {
|
|||
impl<'tcx> ConstVariableValue<'tcx> {
|
||||
/// If this value is known, returns the const it is known to be.
|
||||
/// Otherwise, `None`.
|
||||
pub fn known(&self) -> Option<ty::Const<'tcx>> {
|
||||
pub(crate) fn known(&self) -> Option<ty::Const<'tcx>> {
|
||||
match *self {
|
||||
ConstVariableValue::Unknown { .. } => None,
|
||||
ConstVariableValue::Known { value } => Some(value),
|
||||
|
|
@ -117,7 +113,7 @@ impl<'tcx> ConstVariableValue<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||
pub struct ConstVidKey<'tcx> {
|
||||
pub(crate) struct ConstVidKey<'tcx> {
|
||||
pub vid: ty::ConstVid,
|
||||
pub phantom: PhantomData<ty::Const<'tcx>>,
|
||||
}
|
||||
|
|
@ -832,20 +832,20 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
sess.time("misc_checking_1", || {
|
||||
parallel!(
|
||||
{
|
||||
sess.time("looking_for_entry_point", || tcx.ensure().entry_fn(()));
|
||||
sess.time("looking_for_entry_point", || tcx.ensure_ok().entry_fn(()));
|
||||
|
||||
sess.time("looking_for_derive_registrar", || {
|
||||
tcx.ensure().proc_macro_decls_static(())
|
||||
tcx.ensure_ok().proc_macro_decls_static(())
|
||||
});
|
||||
|
||||
CStore::from_tcx(tcx).report_unused_deps(tcx);
|
||||
},
|
||||
{
|
||||
tcx.hir().par_for_each_module(|module| {
|
||||
tcx.ensure().check_mod_loops(module);
|
||||
tcx.ensure().check_mod_attrs(module);
|
||||
tcx.ensure().check_mod_naked_functions(module);
|
||||
tcx.ensure().check_mod_unstable_api_usage(module);
|
||||
tcx.ensure_ok().check_mod_loops(module);
|
||||
tcx.ensure_ok().check_mod_attrs(module);
|
||||
tcx.ensure_ok().check_mod_naked_functions(module);
|
||||
tcx.ensure_ok().check_mod_unstable_api_usage(module);
|
||||
});
|
||||
},
|
||||
{
|
||||
|
|
@ -858,8 +858,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
// since they might not otherwise get called.
|
||||
// This marks the corresponding crate-level attributes
|
||||
// as used, and ensures that their values are valid.
|
||||
tcx.ensure().limits(());
|
||||
tcx.ensure().stability_index(());
|
||||
tcx.ensure_ok().limits(());
|
||||
tcx.ensure_ok().stability_index(());
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
@ -868,7 +868,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
sess.time("MIR_coroutine_by_move_body", || {
|
||||
tcx.hir().par_body_owners(|def_id| {
|
||||
if tcx.needs_coroutine_by_move_body_def_id(def_id.to_def_id()) {
|
||||
tcx.ensure_with_value().coroutine_by_move_body_def_id(def_id);
|
||||
tcx.ensure_done().coroutine_by_move_body_def_id(def_id);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -883,13 +883,13 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
tcx.hir().par_body_owners(|def_id| {
|
||||
// Run unsafety check because it's responsible for stealing and
|
||||
// deallocating THIR.
|
||||
tcx.ensure().check_unsafety(def_id);
|
||||
tcx.ensure().mir_borrowck(def_id)
|
||||
tcx.ensure_ok().check_unsafety(def_id);
|
||||
tcx.ensure_ok().mir_borrowck(def_id)
|
||||
});
|
||||
});
|
||||
sess.time("MIR_effect_checking", || {
|
||||
tcx.hir().par_body_owners(|def_id| {
|
||||
tcx.ensure().has_ffi_unwind_calls(def_id);
|
||||
tcx.ensure_ok().has_ffi_unwind_calls(def_id);
|
||||
|
||||
// If we need to codegen, ensure that we emit all errors from
|
||||
// `mir_drops_elaborated_and_const_checked` now, to avoid discovering
|
||||
|
|
@ -897,15 +897,15 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
if tcx.sess.opts.output_types.should_codegen()
|
||||
|| tcx.hir().body_const_context(def_id).is_some()
|
||||
{
|
||||
tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
|
||||
tcx.ensure_ok().mir_drops_elaborated_and_const_checked(def_id);
|
||||
}
|
||||
});
|
||||
});
|
||||
sess.time("coroutine_obligations", || {
|
||||
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(
|
||||
tcx.ensure_ok().mir_coroutine_witnesses(def_id);
|
||||
tcx.ensure_ok().check_coroutine_obligations(
|
||||
tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(),
|
||||
);
|
||||
}
|
||||
|
|
@ -950,15 +950,16 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
|
|||
sess.time("misc_checking_3", || {
|
||||
parallel!(
|
||||
{
|
||||
tcx.ensure().effective_visibilities(());
|
||||
tcx.ensure_ok().effective_visibilities(());
|
||||
|
||||
parallel!(
|
||||
{
|
||||
tcx.ensure().check_private_in_public(());
|
||||
tcx.ensure_ok().check_private_in_public(());
|
||||
},
|
||||
{
|
||||
tcx.hir()
|
||||
.par_for_each_module(|module| tcx.ensure().check_mod_deathness(module));
|
||||
tcx.hir().par_for_each_module(|module| {
|
||||
tcx.ensure_ok().check_mod_deathness(module)
|
||||
});
|
||||
},
|
||||
{
|
||||
sess.time("lint_checking", || {
|
||||
|
|
@ -966,14 +967,14 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
|
|||
});
|
||||
},
|
||||
{
|
||||
tcx.ensure().clashing_extern_declarations(());
|
||||
tcx.ensure_ok().clashing_extern_declarations(());
|
||||
}
|
||||
);
|
||||
},
|
||||
{
|
||||
sess.time("privacy_checking_modules", || {
|
||||
tcx.hir().par_for_each_module(|module| {
|
||||
tcx.ensure().check_mod_privacy(module);
|
||||
tcx.ensure_ok().check_mod_privacy(module);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -981,7 +982,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
|
|||
|
||||
// This check has to be run after all lints are done processing. We don't
|
||||
// define a lint filter, as all lint checks should have finished at this point.
|
||||
sess.time("check_lint_expectations", || tcx.ensure().check_expectations(None));
|
||||
sess.time("check_lint_expectations", || tcx.ensure_ok().check_expectations(None));
|
||||
|
||||
// This query is only invoked normally if a diagnostic is emitted that needs any
|
||||
// diagnostic item. If the crate compiles without checking any diagnostic items,
|
||||
|
|
@ -1006,7 +1007,7 @@ fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
|
|||
)
|
||||
}) =>
|
||||
{
|
||||
tcx.ensure().trigger_delayed_bug(def_id);
|
||||
tcx.ensure_ok().trigger_delayed_bug(def_id);
|
||||
}
|
||||
|
||||
// Bare `#[rustc_error]`.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
|
|||
use rustc_hir::intravisit::FnKind as HirFnKind;
|
||||
use rustc_hir::{Body, FnDecl, GenericParamKind, PatKind, PredicateOrigin};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef};
|
||||
|
|
@ -2029,7 +2028,7 @@ impl ExplicitOutlivesRequirements {
|
|||
}
|
||||
|
||||
let span = bound.span().find_ancestor_inside(predicate_span)?;
|
||||
if in_external_macro(tcx.sess, span) {
|
||||
if span.in_external_macro(tcx.sess.source_map()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ pub(super) fn unexpected_cfg_name(
|
|||
};
|
||||
|
||||
let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
|
||||
let is_from_external_macro = rustc_middle::lint::in_external_macro(sess, name_span);
|
||||
let is_from_external_macro = name_span.in_external_macro(sess.source_map());
|
||||
let mut is_feature_cfg = name == sym::feature;
|
||||
|
||||
let code_sugg = if is_feature_cfg && is_from_cargo {
|
||||
|
|
@ -281,7 +281,7 @@ pub(super) fn unexpected_cfg_value(
|
|||
.collect();
|
||||
|
||||
let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
|
||||
let is_from_external_macro = rustc_middle::lint::in_external_macro(sess, name_span);
|
||||
let is_from_external_macro = name_span.in_external_macro(sess.source_map());
|
||||
|
||||
// Show the full list if all possible values for a given name, but don't do it
|
||||
// for names as the possibilities could be very long
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) {
|
|||
|| {
|
||||
tcx.sess.time("module_lints", || {
|
||||
// Run per-module lints
|
||||
tcx.hir().par_for_each_module(|module| tcx.ensure().lint_mod(module));
|
||||
tcx.hir().par_for_each_module(|module| tcx.ensure_ok().lint_mod(module));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use rustc_ast as ast;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_parse_format::{ParseMode, Parser, Piece};
|
||||
use rustc_session::lint::FutureIncompatibilityReason;
|
||||
|
|
@ -100,7 +99,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
|||
|
||||
let (span, panic, symbol) = panic_call(cx, f);
|
||||
|
||||
if in_external_macro(cx.sess(), span) {
|
||||
if span.in_external_macro(cx.sess().source_map()) {
|
||||
// Nothing that can be done about it in the current crate.
|
||||
return;
|
||||
}
|
||||
|
|
@ -229,14 +228,15 @@ fn check_panic_str<'tcx>(
|
|||
|
||||
let (span, _, _) = panic_call(cx, f);
|
||||
|
||||
if in_external_macro(cx.sess(), span) && in_external_macro(cx.sess(), arg.span) {
|
||||
let sm = cx.sess().source_map();
|
||||
if span.in_external_macro(sm) && arg.span.in_external_macro(sm) {
|
||||
// Nothing that can be done about it in the current crate.
|
||||
return;
|
||||
}
|
||||
|
||||
let fmt_span = arg.span.source_callsite();
|
||||
|
||||
let (snippet, style) = match cx.sess().psess.source_map().span_to_snippet(fmt_span) {
|
||||
let (snippet, style) = match sm.span_to_snippet(fmt_span) {
|
||||
Ok(snippet) => {
|
||||
// Count the number of `#`s between the `r` and `"`.
|
||||
let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
|
||||
|
|
@ -283,7 +283,7 @@ fn check_panic_str<'tcx>(
|
|||
/// Given the span of `some_macro!(args);`, gives the span of `(` and `)`,
|
||||
/// and the type of (opening) delimiter used.
|
||||
fn find_delimiters(cx: &LateContext<'_>, span: Span) -> Option<(Span, Span, char)> {
|
||||
let snippet = cx.sess().psess.source_map().span_to_snippet(span).ok()?;
|
||||
let snippet = cx.sess().source_map().span_to_snippet(span).ok()?;
|
||||
let (open, open_ch) = snippet.char_indices().find(|&(_, c)| "([{".contains(c))?;
|
||||
let close = snippet.rfind(|c| ")]}".contains(c))?;
|
||||
Some((
|
||||
|
|
|
|||
|
|
@ -42,6 +42,23 @@ macro_rules! pluralize {
|
|||
};
|
||||
}
|
||||
|
||||
/// Grammatical tool for displaying messages to end users in a nice form.
|
||||
///
|
||||
/// Take a list of items and a function to turn those items into a `String`, and output a display
|
||||
/// friendly comma separated list of those items.
|
||||
// FIXME(estebank): this needs to be changed to go through the translation machinery.
|
||||
pub fn listify<T>(list: &[T], fmt: impl Fn(&T) -> String) -> Option<String> {
|
||||
Some(match list {
|
||||
[only] => fmt(&only),
|
||||
[others @ .., last] => format!(
|
||||
"{} and {}",
|
||||
others.iter().map(|i| fmt(i)).collect::<Vec<_>>().join(", "),
|
||||
fmt(&last),
|
||||
),
|
||||
[] => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Indicates the confidence in the correctness of a suggestion.
|
||||
///
|
||||
/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
|
||||
|
|
|
|||
|
|
@ -118,11 +118,17 @@ struct QueryModifiers {
|
|||
/// Generate a `feed` method to set the query's value from another query.
|
||||
feedable: Option<Ident>,
|
||||
|
||||
/// Forward the result on ensure if the query gets recomputed, and
|
||||
/// return `Ok(())` otherwise. Only applicable to queries returning
|
||||
/// `Result<T, ErrorGuaranteed>`. The `T` is not returned from `ensure`
|
||||
/// invocations.
|
||||
ensure_forwards_result_if_red: Option<Ident>,
|
||||
/// When this query is called via `tcx.ensure_ok()`, it returns
|
||||
/// `Result<(), ErrorGuaranteed>` instead of `()`. If the query needs to
|
||||
/// be executed, and that execution returns an error, the error result is
|
||||
/// returned to the caller.
|
||||
///
|
||||
/// If execution is skipped, a synthetic `Ok(())` is returned, on the
|
||||
/// assumption that a query with all-green inputs must have succeeded.
|
||||
///
|
||||
/// Can only be applied to queries with a return value of
|
||||
/// `Result<_, ErrorGuaranteed>`.
|
||||
return_result_from_ensure_ok: Option<Ident>,
|
||||
}
|
||||
|
||||
fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
||||
|
|
@ -138,7 +144,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
|||
let mut depth_limit = None;
|
||||
let mut separate_provide_extern = None;
|
||||
let mut feedable = None;
|
||||
let mut ensure_forwards_result_if_red = None;
|
||||
let mut return_result_from_ensure_ok = None;
|
||||
|
||||
while !input.is_empty() {
|
||||
let modifier: Ident = input.parse()?;
|
||||
|
|
@ -200,8 +206,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
|||
try_insert!(separate_provide_extern = modifier);
|
||||
} else if modifier == "feedable" {
|
||||
try_insert!(feedable = modifier);
|
||||
} else if modifier == "ensure_forwards_result_if_red" {
|
||||
try_insert!(ensure_forwards_result_if_red = modifier);
|
||||
} else if modifier == "return_result_from_ensure_ok" {
|
||||
try_insert!(return_result_from_ensure_ok = modifier);
|
||||
} else {
|
||||
return Err(Error::new(modifier.span(), "unknown query modifier"));
|
||||
}
|
||||
|
|
@ -222,7 +228,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
|||
depth_limit,
|
||||
separate_provide_extern,
|
||||
feedable,
|
||||
ensure_forwards_result_if_red,
|
||||
return_result_from_ensure_ok,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -354,7 +360,7 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||
eval_always,
|
||||
depth_limit,
|
||||
separate_provide_extern,
|
||||
ensure_forwards_result_if_red,
|
||||
return_result_from_ensure_ok,
|
||||
);
|
||||
|
||||
if modifiers.cache.is_some() {
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ macro_rules! provide_one {
|
|||
// doesn't need to do this (and can't, as it would cause a query cycle).
|
||||
use rustc_middle::dep_graph::dep_kinds;
|
||||
if dep_kinds::$name != dep_kinds::crate_hash && $tcx.dep_graph.is_fully_enabled() {
|
||||
$tcx.ensure().crate_hash($def_id.krate);
|
||||
$tcx.ensure_ok().crate_hash($def_id.krate);
|
||||
}
|
||||
|
||||
let cdata = rustc_data_structures::sync::FreezeReadGuard::map(CStore::from_tcx($tcx), |c| {
|
||||
|
|
|
|||
|
|
@ -2191,13 +2191,13 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
|
|||
let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
|
||||
|
||||
if encode_const {
|
||||
tcx.ensure_with_value().mir_for_ctfe(def_id);
|
||||
tcx.ensure_done().mir_for_ctfe(def_id);
|
||||
}
|
||||
if encode_opt {
|
||||
tcx.ensure_with_value().optimized_mir(def_id);
|
||||
tcx.ensure_done().optimized_mir(def_id);
|
||||
}
|
||||
if encode_opt || encode_const {
|
||||
tcx.ensure_with_value().promoted_mir(def_id);
|
||||
tcx.ensure_done().promoted_mir(def_id);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
pub mod canonical;
|
||||
pub mod unify_key;
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ use rustc_macros::{Decodable, Encodable, HashStable};
|
|||
use rustc_session::Session;
|
||||
use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS};
|
||||
use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId};
|
||||
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Span, Symbol, kw};
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, kw};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::ty::TyCtxt;
|
||||
|
|
@ -201,7 +200,7 @@ impl LintExpectation {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn explain_lint_level_source(
|
||||
fn explain_lint_level_source(
|
||||
lint: &'static Lint,
|
||||
level: Level,
|
||||
src: LintLevelSource,
|
||||
|
|
@ -325,7 +324,7 @@ pub fn lint_level(
|
|||
// If this code originates in a foreign macro, aka something that this crate
|
||||
// did not itself author, then it's likely that there's nothing this crate
|
||||
// can do about it. We probably want to skip the lint entirely.
|
||||
if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
|
||||
if err.span.primary_spans().iter().any(|s| s.in_external_macro(sess.source_map())) {
|
||||
// Any suggestions made here are likely to be incorrect, so anything we
|
||||
// emit shouldn't be automatically fixed by rustfix.
|
||||
err.disable_suggestions();
|
||||
|
|
@ -422,36 +421,3 @@ pub fn lint_level(
|
|||
}
|
||||
lint_level_impl(sess, lint, level, src, span, Box::new(decorate))
|
||||
}
|
||||
|
||||
/// Returns whether `span` originates in a foreign crate's external macro.
|
||||
///
|
||||
/// This is used to test whether a lint should not even begin to figure out whether it should
|
||||
/// be reported on the current node.
|
||||
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
|
||||
let expn_data = span.ctxt().outer_expn_data();
|
||||
match expn_data.kind {
|
||||
ExpnKind::Root
|
||||
| ExpnKind::Desugaring(
|
||||
DesugaringKind::ForLoop
|
||||
| DesugaringKind::WhileLoop
|
||||
| DesugaringKind::OpaqueTy
|
||||
| DesugaringKind::Async
|
||||
| DesugaringKind::Await,
|
||||
) => false,
|
||||
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
|
||||
ExpnKind::Macro(MacroKind::Bang, _) => {
|
||||
// Dummy span for the `def_site` means it's an external macro.
|
||||
expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site)
|
||||
}
|
||||
ExpnKind::Macro { .. } => true, // definitely a plugin
|
||||
}
|
||||
}
|
||||
|
||||
/// Return whether `span` is generated by `async` or `await`.
|
||||
pub fn is_from_async_await(span: Span) -> bool {
|
||||
let expn_data = span.ctxt().outer_expn_data();
|
||||
match expn_data.kind {
|
||||
ExpnKind::Desugaring(DesugaringKind::Async | DesugaringKind::Await) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use super::{
|
|||
ReportedErrorInfo,
|
||||
};
|
||||
use crate::mir;
|
||||
use crate::query::TyCtxtEnsure;
|
||||
use crate::query::TyCtxtEnsureOk;
|
||||
use crate::ty::visit::TypeVisitableExt;
|
||||
use crate::ty::{self, GenericArgs, TyCtxt};
|
||||
|
||||
|
|
@ -198,7 +198,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxtEnsure<'tcx> {
|
||||
impl<'tcx> TyCtxtEnsureOk<'tcx> {
|
||||
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
|
||||
/// that can't take any generic arguments like const items or enum discriminants. If a
|
||||
/// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned.
|
||||
|
|
|
|||
|
|
@ -92,51 +92,88 @@ impl<'tcx> MonoItem<'tcx> {
|
|||
}
|
||||
|
||||
pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
|
||||
let generate_cgu_internal_copies =
|
||||
(tcx.sess.opts.optimize != OptLevel::No) && !tcx.sess.link_dead_code();
|
||||
// The case handling here is written in the same style as cross_crate_inlinable, we first
|
||||
// handle the cases where we must use a particular instantiation mode, then cascade down
|
||||
// through a sequence of heuristics.
|
||||
|
||||
match *self {
|
||||
MonoItem::Fn(ref instance) => {
|
||||
let entry_def_id = tcx.entry_fn(()).map(|(id, _)| id);
|
||||
// If this function isn't inlined or otherwise has an extern
|
||||
// indicator, then we'll be creating a globally shared version.
|
||||
let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
|
||||
if codegen_fn_attrs.contains_extern_indicator()
|
||||
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
|
||||
|| !instance.def.generates_cgu_internal_copy(tcx)
|
||||
|| Some(instance.def_id()) == entry_def_id
|
||||
{
|
||||
return InstantiationMode::GloballyShared { may_conflict: false };
|
||||
}
|
||||
// The first thing we do is detect MonoItems which we must instantiate exactly once in the
|
||||
// whole program.
|
||||
|
||||
if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline
|
||||
&& self.is_generic_fn()
|
||||
{
|
||||
// Upgrade inline(never) to a globally shared instance.
|
||||
return InstantiationMode::GloballyShared { may_conflict: true };
|
||||
}
|
||||
|
||||
// At this point we don't have explicit linkage and we're an
|
||||
// inlined function. If this crate's build settings permit,
|
||||
// we'll be creating a local copy per CGU.
|
||||
if generate_cgu_internal_copies {
|
||||
return InstantiationMode::LocalCopy;
|
||||
}
|
||||
|
||||
// Finally, if this is `#[inline(always)]` we're sure to respect
|
||||
// that with an inline copy per CGU, but otherwise we'll be
|
||||
// creating one copy of this `#[inline]` function which may
|
||||
// conflict with upstream crates as it could be an exported
|
||||
// symbol.
|
||||
if tcx.codegen_fn_attrs(instance.def_id()).inline.always() {
|
||||
InstantiationMode::LocalCopy
|
||||
} else {
|
||||
InstantiationMode::GloballyShared { may_conflict: true }
|
||||
}
|
||||
}
|
||||
// Statics and global_asm! must be instantiated exactly once.
|
||||
let instance = match *self {
|
||||
MonoItem::Fn(instance) => instance,
|
||||
MonoItem::Static(..) | MonoItem::GlobalAsm(..) => {
|
||||
InstantiationMode::GloballyShared { may_conflict: false }
|
||||
return InstantiationMode::GloballyShared { may_conflict: false };
|
||||
}
|
||||
};
|
||||
|
||||
// Similarly, the executable entrypoint must be instantiated exactly once.
|
||||
if let Some((entry_def_id, _)) = tcx.entry_fn(()) {
|
||||
if instance.def_id() == entry_def_id {
|
||||
return InstantiationMode::GloballyShared { may_conflict: false };
|
||||
}
|
||||
}
|
||||
|
||||
// If the function is #[naked] or contains any other attribute that requires exactly-once
|
||||
// instantiation:
|
||||
let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
|
||||
if codegen_fn_attrs.contains_extern_indicator()
|
||||
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
|
||||
{
|
||||
return InstantiationMode::GloballyShared { may_conflict: false };
|
||||
}
|
||||
|
||||
// FIXME: The logic for which functions are permitted to get LocalCopy is actually spread
|
||||
// across 4 functions:
|
||||
// * cross_crate_inlinable(def_id)
|
||||
// * InstanceKind::requires_inline
|
||||
// * InstanceKind::generate_cgu_internal_copy
|
||||
// * MonoItem::instantiation_mode
|
||||
// Since reachable_non_generics calls InstanceKind::generates_cgu_internal_copy to decide
|
||||
// which symbols this crate exports, we are obligated to only generate LocalCopy when
|
||||
// generates_cgu_internal_copy returns true.
|
||||
if !instance.def.generates_cgu_internal_copy(tcx) {
|
||||
return InstantiationMode::GloballyShared { may_conflict: false };
|
||||
}
|
||||
|
||||
// Beginning of heuristics. The handling of link-dead-code and inline(always) are QoL only,
|
||||
// the compiler should not crash and linkage should work, but codegen may be undesirable.
|
||||
|
||||
// -Clink-dead-code was given an unfortunate name; the point of the flag is to assist
|
||||
// coverage tools which rely on having every function in the program appear in the
|
||||
// generated code. If we select LocalCopy, functions which are not used because they are
|
||||
// missing test coverage will disappear from such coverage reports, defeating the point.
|
||||
// Note that -Cinstrument-coverage does not require such assistance from us, only coverage
|
||||
// tools implemented without compiler support ironically require a special compiler flag.
|
||||
if tcx.sess.link_dead_code() {
|
||||
return InstantiationMode::GloballyShared { may_conflict: true };
|
||||
}
|
||||
|
||||
// To ensure that #[inline(always)] can be inlined as much as possible, especially in unoptimized
|
||||
// builds, we always select LocalCopy.
|
||||
if codegen_fn_attrs.inline.always() {
|
||||
return InstantiationMode::LocalCopy;
|
||||
}
|
||||
|
||||
// #[inline(never)] functions in general are poor candidates for inlining and thus since
|
||||
// LocalCopy generally increases code size for the benefit of optimizations from inlining,
|
||||
// we want to give them GloballyShared codegen.
|
||||
// The slight problem is that generic functions need to always support cross-crate
|
||||
// compilation, so all previous stages of the compiler are obligated to treat generic
|
||||
// functions the same as those that unconditionally get LocalCopy codegen. It's only when
|
||||
// we get here that we can at least not codegen a #[inline(never)] generic function in all
|
||||
// of our CGUs.
|
||||
if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline
|
||||
&& self.is_generic_fn()
|
||||
{
|
||||
return InstantiationMode::GloballyShared { may_conflict: true };
|
||||
}
|
||||
|
||||
// The fallthrough case is to generate LocalCopy for all optimized builds, and
|
||||
// GloballyShared with conflict prevention when optimizations are disabled.
|
||||
match tcx.sess.opts.optimize {
|
||||
OptLevel::No => InstantiationMode::GloballyShared { may_conflict: true },
|
||||
_ => InstantiationMode::LocalCopy,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1248,6 +1248,10 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
ShallowInitBox(ref place, ref ty) => {
|
||||
with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})"))
|
||||
}
|
||||
|
||||
WrapUnsafeBinder(ref op, ty) => {
|
||||
with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1308,6 +1312,9 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
|
|||
ProjectionElem::Index(_)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. } => {}
|
||||
ProjectionElem::UnwrapUnsafeBinder(_) => {
|
||||
write!(fmt, "unwrap_binder!(")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1356,6 +1363,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
|
|||
ProjectionElem::Subslice { from, to, from_end: false } => {
|
||||
write!(fmt, "[{from:?}..{to:?}]")?;
|
||||
}
|
||||
ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||
write!(fmt, "; {ty})")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
| Self::Subtype(_)
|
||||
| Self::ConstantIndex { .. }
|
||||
| Self::Subslice { .. }
|
||||
| Self::Downcast(_, _) => false,
|
||||
| Self::Downcast(_, _)
|
||||
| Self::UnwrapUnsafeBinder(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +77,8 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
| Self::Subtype(_)
|
||||
| Self::ConstantIndex { .. }
|
||||
| Self::Subslice { .. }
|
||||
| Self::Downcast(_, _) => true,
|
||||
| Self::Downcast(_, _)
|
||||
| Self::UnwrapUnsafeBinder(..) => true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,6 +104,9 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
| Self::Subtype(_)
|
||||
| Self::OpaqueCast(_)
|
||||
| Self::Subslice { .. } => false,
|
||||
|
||||
// FIXME(unsafe_binders): Figure this out.
|
||||
Self::UnwrapUnsafeBinder(..) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -443,7 +448,8 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
| Rvalue::UnaryOp(_, _)
|
||||
| Rvalue::Discriminant(_)
|
||||
| Rvalue::Aggregate(_, _)
|
||||
| Rvalue::ShallowInitBox(_, _) => true,
|
||||
| Rvalue::ShallowInitBox(_, _)
|
||||
| Rvalue::WrapUnsafeBinder(_, _) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1276,6 +1276,10 @@ pub enum ProjectionElem<V, T> {
|
|||
/// requiring an intermediate variable.
|
||||
OpaqueCast(T),
|
||||
|
||||
/// A transmute from an unsafe binder to the type that it wraps. This is a projection
|
||||
/// of a place, so it doesn't necessarily constitute a move out of the binder.
|
||||
UnwrapUnsafeBinder(T),
|
||||
|
||||
/// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
|
||||
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
|
||||
/// explicit during optimizations and codegen.
|
||||
|
|
@ -1493,6 +1497,9 @@ pub enum Rvalue<'tcx> {
|
|||
/// optimizations and codegen backends that previously had to handle deref operations anywhere
|
||||
/// in a place.
|
||||
CopyForDeref(Place<'tcx>),
|
||||
|
||||
/// Wraps a value in an unsafe binder.
|
||||
WrapUnsafeBinder(Operand<'tcx>, Ty<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
|
|
|
|||
|
|
@ -146,6 +146,11 @@ impl<'tcx> PlaceTy<'tcx> {
|
|||
ProjectionElem::Subtype(ty) => {
|
||||
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
|
||||
}
|
||||
|
||||
// FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
|
||||
ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
|
||||
}
|
||||
};
|
||||
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
|
||||
answer
|
||||
|
|
@ -241,6 +246,7 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
},
|
||||
Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
|
||||
Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
|
||||
Rvalue::WrapUnsafeBinder(_, ty) => ty,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! `TypeFoldable` implementations for MIR types
|
||||
|
||||
use rustc_ast::InlineAsmTemplatePiece;
|
||||
use rustc_hir::UnsafeBinderCastKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
|
||||
use super::*;
|
||||
|
|
@ -21,6 +22,7 @@ TrivialTypeTraversalImpls! {
|
|||
SwitchTargets,
|
||||
CoroutineKind,
|
||||
CoroutineSavedLocal,
|
||||
UnsafeBinderCastKind,
|
||||
}
|
||||
|
||||
TrivialTypeTraversalImpls! {
|
||||
|
|
|
|||
|
|
@ -781,6 +781,11 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_operand(operand, location);
|
||||
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
||||
}
|
||||
|
||||
Rvalue::WrapUnsafeBinder(op, ty) => {
|
||||
self.visit_operand(op, location);
|
||||
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1151,6 +1156,11 @@ macro_rules! visit_place_fns {
|
|||
self.visit_ty(&mut new_ty, TyContext::Location(location));
|
||||
if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
|
||||
}
|
||||
PlaceElem::UnwrapUnsafeBinder(ty) => {
|
||||
let mut new_ty = ty;
|
||||
self.visit_ty(&mut new_ty, TyContext::Location(location));
|
||||
if ty != new_ty { Some(PlaceElem::UnwrapUnsafeBinder(new_ty)) } else { None }
|
||||
}
|
||||
PlaceElem::Deref
|
||||
| PlaceElem::ConstantIndex { .. }
|
||||
| PlaceElem::Subslice { .. }
|
||||
|
|
@ -1219,7 +1229,8 @@ macro_rules! visit_place_fns {
|
|||
match elem {
|
||||
ProjectionElem::OpaqueCast(ty)
|
||||
| ProjectionElem::Subtype(ty)
|
||||
| ProjectionElem::Field(_, ty) => {
|
||||
| ProjectionElem::Field(_, ty)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||
self.visit_ty(ty, TyContext::Location(location));
|
||||
}
|
||||
ProjectionElem::Index(local) => {
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ pub use keys::{AsLocalKey, Key, LocalCrate};
|
|||
pub mod on_disk_cache;
|
||||
#[macro_use]
|
||||
pub mod plumbing;
|
||||
pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue};
|
||||
pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk};
|
||||
|
||||
// Each of these queries corresponds to a function pointer field in the
|
||||
// `Providers` struct for requesting a value of that type, and a method
|
||||
|
|
@ -1087,7 +1087,7 @@ rustc_queries! {
|
|||
|
||||
query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> {
|
||||
desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) }
|
||||
ensure_forwards_result_if_red
|
||||
return_result_from_ensure_ok
|
||||
}
|
||||
|
||||
/// Caches `CoerceUnsized` kinds for impls on custom types.
|
||||
|
|
@ -1095,7 +1095,7 @@ rustc_queries! {
|
|||
desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
separate_provide_extern
|
||||
ensure_forwards_result_if_red
|
||||
return_result_from_ensure_ok
|
||||
}
|
||||
|
||||
query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
|
||||
|
|
@ -1110,7 +1110,7 @@ rustc_queries! {
|
|||
|
||||
query coherent_trait(def_id: DefId) -> Result<(), ErrorGuaranteed> {
|
||||
desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) }
|
||||
ensure_forwards_result_if_red
|
||||
return_result_from_ensure_ok
|
||||
}
|
||||
|
||||
/// Borrow-checks the function body. If this is a closure, returns
|
||||
|
|
@ -1140,7 +1140,7 @@ rustc_queries! {
|
|||
/// </div>
|
||||
query crate_inherent_impls_validity_check(_: ()) -> Result<(), ErrorGuaranteed> {
|
||||
desc { "check for inherent impls that should not be defined in crate" }
|
||||
ensure_forwards_result_if_red
|
||||
return_result_from_ensure_ok
|
||||
}
|
||||
|
||||
/// Checks all types in the crate for overlap in their inherent impls. Reports errors.
|
||||
|
|
@ -1152,7 +1152,7 @@ rustc_queries! {
|
|||
/// </div>
|
||||
query crate_inherent_impls_overlap_check(_: ()) -> Result<(), ErrorGuaranteed> {
|
||||
desc { "check for overlap between inherent impls defined in this crate" }
|
||||
ensure_forwards_result_if_red
|
||||
return_result_from_ensure_ok
|
||||
}
|
||||
|
||||
/// Checks whether all impls in the crate pass the overlap check, returning
|
||||
|
|
@ -1162,7 +1162,7 @@ rustc_queries! {
|
|||
"checking whether impl `{}` follows the orphan rules",
|
||||
tcx.def_path_str(key),
|
||||
}
|
||||
ensure_forwards_result_if_red
|
||||
return_result_from_ensure_ok
|
||||
}
|
||||
|
||||
/// Check whether the function has any recursion that could cause the inliner to trigger
|
||||
|
|
@ -1479,7 +1479,7 @@ rustc_queries! {
|
|||
query specialization_graph_of(trait_id: DefId) -> Result<&'tcx specialization_graph::Graph, ErrorGuaranteed> {
|
||||
desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
|
||||
cache_on_disk_if { true }
|
||||
ensure_forwards_result_if_red
|
||||
return_result_from_ensure_ok
|
||||
}
|
||||
query dyn_compatibility_violations(trait_id: DefId) -> &'tcx [DynCompatibilityViolation] {
|
||||
desc { |tcx| "determining dyn-compatibility of trait `{}`", tcx.def_path_str(trait_id) }
|
||||
|
|
@ -1715,12 +1715,12 @@ rustc_queries! {
|
|||
|
||||
query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
|
||||
desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) }
|
||||
ensure_forwards_result_if_red
|
||||
return_result_from_ensure_ok
|
||||
}
|
||||
|
||||
query enforce_impl_non_lifetime_params_are_constrained(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
|
||||
desc { |tcx| "checking that `{}`'s generics are constrained by the impl header", tcx.def_path_str(key) }
|
||||
ensure_forwards_result_if_red
|
||||
return_result_from_ensure_ok
|
||||
}
|
||||
|
||||
// The `DefId`s of all non-generic functions and statics in the given crate
|
||||
|
|
@ -2442,7 +2442,7 @@ rustc_queries! {
|
|||
/// Any other def id will ICE.
|
||||
query compare_impl_item(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
|
||||
desc { |tcx| "checking assoc item `{}` is compatible with trait definition", tcx.def_path_str(key) }
|
||||
ensure_forwards_result_if_red
|
||||
return_result_from_ensure_ok
|
||||
}
|
||||
|
||||
query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] {
|
||||
|
|
|
|||
|
|
@ -88,30 +88,68 @@ impl<'tcx> Deref for TyCtxtAt<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TyCtxtEnsure<'tcx> {
|
||||
#[must_use]
|
||||
pub struct TyCtxtEnsureOk<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TyCtxtEnsureWithValue<'tcx> {
|
||||
#[must_use]
|
||||
pub struct TyCtxtEnsureDone<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Returns a transparent wrapper for `TyCtxt`, which ensures queries
|
||||
/// are executed instead of just returning their results.
|
||||
/// Wrapper that calls queries in a special "ensure OK" mode, for callers
|
||||
/// that don't need the return value and just want to invoke a query for
|
||||
/// its potential side-effect of emitting fatal errors.
|
||||
///
|
||||
/// This can be more efficient than a normal query call, because if the
|
||||
/// query's inputs are all green, the call can return immediately without
|
||||
/// needing to obtain a value (by decoding one from disk or by executing
|
||||
/// the query).
|
||||
///
|
||||
/// (As with all query calls, execution is also skipped if the query result
|
||||
/// is already cached in memory.)
|
||||
///
|
||||
/// ## WARNING
|
||||
/// A subsequent normal call to the same query might still cause it to be
|
||||
/// executed! This can occur when the inputs are all green, but the query's
|
||||
/// result is not cached on disk, so the query must be executed to obtain a
|
||||
/// return value.
|
||||
///
|
||||
/// Therefore, this call mode is not appropriate for callers that want to
|
||||
/// ensure that the query is _never_ executed in the future.
|
||||
///
|
||||
/// ## `return_result_from_ensure_ok`
|
||||
/// If a query has the `return_result_from_ensure_ok` modifier, calls via
|
||||
/// `ensure_ok` will instead return `Result<(), ErrorGuaranteed>`. If the
|
||||
/// query needs to be executed, and execution returns an error, that error
|
||||
/// is returned to the caller.
|
||||
#[inline(always)]
|
||||
pub fn ensure(self) -> TyCtxtEnsure<'tcx> {
|
||||
TyCtxtEnsure { tcx: self }
|
||||
pub fn ensure_ok(self) -> TyCtxtEnsureOk<'tcx> {
|
||||
TyCtxtEnsureOk { tcx: self }
|
||||
}
|
||||
|
||||
/// Returns a transparent wrapper for `TyCtxt`, which ensures queries
|
||||
/// are executed instead of just returning their results.
|
||||
/// Wrapper that calls queries in a special "ensure done" mode, for callers
|
||||
/// that don't need the return value and just want to guarantee that the
|
||||
/// query won't be executed in the future, by executing it now if necessary.
|
||||
///
|
||||
/// This version verifies that the computed result exists in the cache before returning.
|
||||
/// This is useful for queries that read from a [`Steal`] value, to ensure
|
||||
/// that they are executed before the query that will steal the value.
|
||||
///
|
||||
/// Unlike [`Self::ensure_ok`], a query with all-green inputs will only be
|
||||
/// skipped if its return value is stored in the disk-cache. This is still
|
||||
/// more efficient than a regular query, because in that situation the
|
||||
/// return value doesn't necessarily need to be decoded.
|
||||
///
|
||||
/// (As with all query calls, execution is also skipped if the query result
|
||||
/// is already cached in memory.)
|
||||
///
|
||||
/// [`Steal`]: rustc_data_structures::steal::Steal
|
||||
#[inline(always)]
|
||||
pub fn ensure_with_value(self) -> TyCtxtEnsureWithValue<'tcx> {
|
||||
TyCtxtEnsureWithValue { tcx: self }
|
||||
pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> {
|
||||
TyCtxtEnsureDone { tcx: self }
|
||||
}
|
||||
|
||||
/// Returns a transparent wrapper for `TyCtxt` which uses
|
||||
|
|
@ -193,7 +231,7 @@ macro_rules! query_ensure {
|
|||
([]$($args:tt)*) => {
|
||||
query_ensure($($args)*)
|
||||
};
|
||||
([(ensure_forwards_result_if_red) $($rest:tt)*]$($args:tt)*) => {
|
||||
([(return_result_from_ensure_ok) $($rest:tt)*]$($args:tt)*) => {
|
||||
query_ensure_error_guaranteed($($args)*).map(|_| ())
|
||||
};
|
||||
([$other:tt $($modifiers:tt)*]$($args:tt)*) => {
|
||||
|
|
@ -248,15 +286,15 @@ macro_rules! separate_provide_extern_decl {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! ensure_result {
|
||||
([][$ty:ty]) => {
|
||||
macro_rules! ensure_ok_result {
|
||||
( [] ) => {
|
||||
()
|
||||
};
|
||||
([(ensure_forwards_result_if_red) $($rest:tt)*][$ty:ty]) => {
|
||||
( [(return_result_from_ensure_ok) $($rest:tt)*] ) => {
|
||||
Result<(), ErrorGuaranteed>
|
||||
};
|
||||
([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
|
||||
ensure_result!([$($modifiers)*][$($args)*])
|
||||
( [$other:tt $($modifiers:tt)*] ) => {
|
||||
ensure_ok_result!( [$($modifiers)*] )
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -383,10 +421,13 @@ macro_rules! define_callbacks {
|
|||
$($(#[$attr])* pub $name: queries::$name::Storage<'tcx>,)*
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxtEnsure<'tcx> {
|
||||
impl<'tcx> TyCtxtEnsureOk<'tcx> {
|
||||
$($(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> ensure_result!([$($modifiers)*][$V]) {
|
||||
pub fn $name(
|
||||
self,
|
||||
key: query_helper_param_ty!($($K)*),
|
||||
) -> ensure_ok_result!([$($modifiers)*]) {
|
||||
query_ensure!(
|
||||
[$($modifiers)*]
|
||||
self.tcx,
|
||||
|
|
@ -398,7 +439,7 @@ macro_rules! define_callbacks {
|
|||
})*
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxtEnsureWithValue<'tcx> {
|
||||
impl<'tcx> TyCtxtEnsureDone<'tcx> {
|
||||
$($(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
|
||||
|
|
|
|||
|
|
@ -489,6 +489,19 @@ pub enum ExprKind<'tcx> {
|
|||
user_ty: UserTy<'tcx>,
|
||||
user_ty_span: Span,
|
||||
},
|
||||
/// An unsafe binder cast on a place, e.g. `unwrap_binder!(*ptr)`.
|
||||
PlaceUnwrapUnsafeBinder {
|
||||
source: ExprId,
|
||||
},
|
||||
/// An unsafe binder cast on a value, e.g. `unwrap_binder!(rvalue())`,
|
||||
/// which makes a temporary.
|
||||
ValueUnwrapUnsafeBinder {
|
||||
source: ExprId,
|
||||
},
|
||||
/// Construct an unsafe binder, e.g. `wrap_binder(&ref)`.
|
||||
WrapUnsafeBinder {
|
||||
source: ExprId,
|
||||
},
|
||||
/// A closure definition.
|
||||
Closure(Box<ClosureExpr<'tcx>>),
|
||||
/// A literal.
|
||||
|
|
|
|||
|
|
@ -136,6 +136,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||
| ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => {
|
||||
visitor.visit_expr(&visitor.thir()[source])
|
||||
}
|
||||
PlaceUnwrapUnsafeBinder { source }
|
||||
| ValueUnwrapUnsafeBinder { source }
|
||||
| WrapUnsafeBinder { source } => visitor.visit_expr(&visitor.thir()[source]),
|
||||
Closure(box ClosureExpr {
|
||||
closure_id: _,
|
||||
args: _,
|
||||
|
|
|
|||
|
|
@ -1957,7 +1957,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap {
|
||||
// Create a dependency to the crate to be sure we re-execute this when the amount of
|
||||
// definitions change.
|
||||
self.ensure().hir_crate(());
|
||||
self.ensure_ok().hir_crate(());
|
||||
// Freeze definitions once we start iterating on them, to prevent adding new ones
|
||||
// while iterating. If some query needs to add definitions, it should be `ensure`d above.
|
||||
self.untracked.definitions.freeze().def_path_hash_to_def_index_map()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::ops::ControlFlow;
|
|||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, pluralize,
|
||||
Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, listify, pluralize,
|
||||
};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
|
@ -362,11 +362,8 @@ pub fn suggest_constraining_type_params<'a>(
|
|||
let n = trait_names.len();
|
||||
let stable = if all_stable { "" } else { "unstable " };
|
||||
let trait_ = if all_known { format!("trait{}", pluralize!(n)) } else { String::new() };
|
||||
format!("{stable}{trait_}{}", match &trait_names[..] {
|
||||
[t] => format!(" {t}"),
|
||||
[ts @ .., last] => format!(" {} and {last}", ts.join(", ")),
|
||||
[] => return false,
|
||||
},)
|
||||
let Some(trait_names) = listify(&trait_names, |n| n.to_string()) else { return false };
|
||||
format!("{stable}{trait_} {trait_names}")
|
||||
} else {
|
||||
// We're more explicit when there's a mix of stable and unstable traits.
|
||||
let mut trait_names = constraints
|
||||
|
|
@ -378,10 +375,9 @@ pub fn suggest_constraining_type_params<'a>(
|
|||
.collect::<Vec<_>>();
|
||||
trait_names.sort();
|
||||
trait_names.dedup();
|
||||
match &trait_names[..] {
|
||||
[t] => t.to_string(),
|
||||
[ts @ .., last] => format!("{} and {last}", ts.join(", ")),
|
||||
[] => return false,
|
||||
match listify(&trait_names, |t| t.to_string()) {
|
||||
Some(names) => names,
|
||||
None => return false,
|
||||
}
|
||||
};
|
||||
let constraint = constraint.join(" + ");
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ use rustc_hir::def::{CtorOf, DefKind};
|
|||
use rustc_macros::extension;
|
||||
pub use rustc_type_ir::error::ExpectedFound;
|
||||
|
||||
use crate::ty::print::{FmtPrinter, PrettyPrinter, with_forced_trimmed_paths};
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use crate::ty::print::{FmtPrinter, Print, with_forced_trimmed_paths};
|
||||
use crate::ty::{self, Lift, Ty, TyCtxt};
|
||||
|
||||
pub type TypeError<'tcx> = rustc_type_ir::error::TypeError<TyCtxt<'tcx>>;
|
||||
|
||||
|
|
@ -159,8 +159,8 @@ impl<'tcx> Ty<'tcx> {
|
|||
ty::Error(_) => "type error".into(),
|
||||
_ => {
|
||||
let width = tcx.sess.diagnostic_width();
|
||||
let length_limit = std::cmp::max(width / 4, 15);
|
||||
format!("`{}`", tcx.ty_string_with_limit(self, length_limit)).into()
|
||||
let length_limit = std::cmp::max(width / 4, 40);
|
||||
format!("`{}`", tcx.string_with_limit(self, length_limit)).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -213,10 +213,14 @@ impl<'tcx> Ty<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
pub fn ty_string_with_limit(self, ty: Ty<'tcx>, length_limit: usize) -> String {
|
||||
pub fn string_with_limit<'a, T>(self, p: T, length_limit: usize) -> String
|
||||
where
|
||||
T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy,
|
||||
<T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>,
|
||||
{
|
||||
let mut type_limit = 50;
|
||||
let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
|
||||
cx.pretty_print_type(ty)
|
||||
self.lift(p).expect("could not lift for printing").print(cx)
|
||||
})
|
||||
.expect("could not write to `String`");
|
||||
if regular.len() <= length_limit {
|
||||
|
|
@ -231,7 +235,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
hir::def::Namespace::TypeNS,
|
||||
rustc_session::Limit(type_limit),
|
||||
);
|
||||
cx.pretty_print_type(ty).expect("could not write to `String`");
|
||||
self.lift(p)
|
||||
.expect("could not lift for printing")
|
||||
.print(&mut cx)
|
||||
.expect("could not print type");
|
||||
cx.into_buffer()
|
||||
});
|
||||
if short.len() <= length_limit || type_limit == 0 {
|
||||
|
|
@ -242,9 +249,17 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
short
|
||||
}
|
||||
|
||||
pub fn short_ty_string(self, ty: Ty<'tcx>, path: &mut Option<PathBuf>) -> String {
|
||||
/// When calling this after a `Diag` is constructed, the preferred way of doing so is
|
||||
/// `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that keeps
|
||||
/// the existence of a "long type" anywhere in the diagnostic, so the note telling the user
|
||||
/// where we wrote the file to is only printed once.
|
||||
pub fn short_string<'a, T>(self, p: T, path: &mut Option<PathBuf>) -> String
|
||||
where
|
||||
T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy + Hash,
|
||||
<T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>,
|
||||
{
|
||||
let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
|
||||
cx.pretty_print_type(ty)
|
||||
self.lift(p).expect("could not lift for printing").print(cx)
|
||||
})
|
||||
.expect("could not write to `String`");
|
||||
|
||||
|
|
@ -257,13 +272,13 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
if regular.len() <= width * 2 / 3 {
|
||||
return regular;
|
||||
}
|
||||
let short = self.ty_string_with_limit(ty, length_limit);
|
||||
let short = self.string_with_limit(p, length_limit);
|
||||
if regular == short {
|
||||
return regular;
|
||||
}
|
||||
// Ensure we create an unique file for the type passed in when we create a file.
|
||||
let mut s = DefaultHasher::new();
|
||||
ty.hash(&mut s);
|
||||
p.hash(&mut s);
|
||||
let hash = s.finish();
|
||||
*path = Some(path.take().unwrap_or_else(|| {
|
||||
self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None)
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ pub use self::sty::{
|
|||
pub use self::trait_def::TraitDef;
|
||||
pub use self::typeck_results::{
|
||||
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
|
||||
TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind,
|
||||
Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind,
|
||||
};
|
||||
pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
|
||||
|
|
|
|||
|
|
@ -105,6 +105,10 @@ pub trait Printer<'tcx>: Sized {
|
|||
args: &[GenericArg<'tcx>],
|
||||
) -> Result<(), PrintError>;
|
||||
|
||||
fn should_truncate(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
// Defaults (should not be overridden):
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue