mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-17 09:23:05 +00:00
Merge from rustc
This commit is contained in:
commit
4014b17d86
@ -1481,7 +1481,7 @@ and related tools.
|
||||
[is_power_of_two_usize]: https://doc.rust-lang.org/stable/core/num/struct.NonZeroUsize.html#method.is_power_of_two
|
||||
[stdarch/1266]: https://github.com/rust-lang/stdarch/pull/1266
|
||||
|
||||
Version 1.58.1 (2022-01-19)
|
||||
Version 1.58.1 (2022-01-20)
|
||||
===========================
|
||||
|
||||
* Fix race condition in `std::fs::remove_dir_all` ([CVE-2022-21658])
|
||||
|
@ -27,3 +27,26 @@ pub fn expand_deriving_copy(
|
||||
|
||||
trait_def.expand(cx, mitem, item, push);
|
||||
}
|
||||
|
||||
pub fn expand_deriving_const_param_ty(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
mitem: &MetaItem,
|
||||
item: &Annotatable,
|
||||
push: &mut dyn FnMut(Annotatable),
|
||||
is_const: bool,
|
||||
) {
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(marker::ConstParamTy),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: false,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods: Vec::new(),
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
};
|
||||
|
||||
trait_def.expand(cx, mitem, item, push);
|
||||
}
|
||||
|
@ -115,6 +115,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
||||
register_derive! {
|
||||
Clone: clone::expand_deriving_clone,
|
||||
Copy: bounds::expand_deriving_copy,
|
||||
ConstParamTy: bounds::expand_deriving_const_param_ty,
|
||||
Debug: debug::expand_deriving_debug,
|
||||
Default: default::expand_deriving_default,
|
||||
Eq: eq::expand_deriving_eq,
|
||||
|
@ -966,11 +966,7 @@ fn codegen_panic_inner<'tcx>(
|
||||
args: &[Value],
|
||||
span: Span,
|
||||
) {
|
||||
let def_id = fx
|
||||
.tcx
|
||||
.lang_items()
|
||||
.require(lang_item)
|
||||
.unwrap_or_else(|e| fx.tcx.sess.span_fatal(span, e.to_string()));
|
||||
let def_id = fx.tcx.require_lang_item(lang_item, Some(span));
|
||||
|
||||
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
|
||||
let symbol_name = fx.tcx.symbol_name(instance).name;
|
||||
|
@ -25,7 +25,6 @@ use std::fs::File;
|
||||
use std::io;
|
||||
use std::iter;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -709,17 +708,6 @@ pub unsafe fn optimize_thin_module(
|
||||
let llmod = module.module_llvm.llmod();
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-input");
|
||||
|
||||
// Before we do much else find the "main" `DICompileUnit` that we'll be
|
||||
// using below. If we find more than one though then rustc has changed
|
||||
// in a way we're not ready for, so generate an ICE by returning
|
||||
// an error.
|
||||
let mut cu1 = ptr::null_mut();
|
||||
let mut cu2 = ptr::null_mut();
|
||||
llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
|
||||
if !cu2.is_null() {
|
||||
return Err(write::llvm_err(&diag_handler, LlvmError::MultipleSourceDiCompileUnit));
|
||||
}
|
||||
|
||||
// Up next comes the per-module local analyses that we do for Thin LTO.
|
||||
// Each of these functions is basically copied from the LLVM
|
||||
// implementation and then tailored to suit this implementation. Ideally
|
||||
@ -766,43 +754,6 @@ pub unsafe fn optimize_thin_module(
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-import");
|
||||
}
|
||||
|
||||
// Ok now this is a bit unfortunate. This is also something you won't
|
||||
// find upstream in LLVM's ThinLTO passes! This is a hack for now to
|
||||
// work around bugs in LLVM.
|
||||
//
|
||||
// First discovered in #45511 it was found that as part of ThinLTO
|
||||
// importing passes LLVM will import `DICompileUnit` metadata
|
||||
// information across modules. This means that we'll be working with one
|
||||
// LLVM module that has multiple `DICompileUnit` instances in it (a
|
||||
// bunch of `llvm.dbg.cu` members). Unfortunately there's a number of
|
||||
// bugs in LLVM's backend which generates invalid DWARF in a situation
|
||||
// like this:
|
||||
//
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=35212
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=35562
|
||||
//
|
||||
// While the first bug there is fixed the second ended up causing #46346
|
||||
// which was basically a resurgence of #45511 after LLVM's bug 35212 was
|
||||
// fixed.
|
||||
//
|
||||
// This function below is a huge hack around this problem. The function
|
||||
// below is defined in `PassWrapper.cpp` and will basically "merge"
|
||||
// all `DICompileUnit` instances in a module. Basically it'll take all
|
||||
// the objects, rewrite all pointers of `DISubprogram` to point to the
|
||||
// first `DICompileUnit`, and then delete all the other units.
|
||||
//
|
||||
// This is probably mangling to the debug info slightly (but hopefully
|
||||
// not too much) but for now at least gets LLVM to emit valid DWARF (or
|
||||
// so it appears). Hopefully we can remove this once upstream bugs are
|
||||
// fixed in LLVM.
|
||||
{
|
||||
let _timer = cgcx
|
||||
.prof
|
||||
.generic_activity_with_arg("LLVM_thin_lto_patch_debuginfo", thin_module.name());
|
||||
llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-patch");
|
||||
}
|
||||
|
||||
// Alright now that we've done everything related to the ThinLTO
|
||||
// analysis it's time to run some optimizations! Here we use the same
|
||||
// `run_pass_manager` as the "fat" LTO above except that we tell it to
|
||||
|
@ -2484,12 +2484,6 @@ extern "C" {
|
||||
len: usize,
|
||||
out_len: &mut usize,
|
||||
) -> *const u8;
|
||||
pub fn LLVMRustThinLTOGetDICompileUnit(
|
||||
M: &Module,
|
||||
CU1: &mut *mut c_void,
|
||||
CU2: &mut *mut c_void,
|
||||
);
|
||||
pub fn LLVMRustThinLTOPatchDICompileUnit(M: &Module, CU: *mut c_void);
|
||||
|
||||
pub fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>;
|
||||
pub fn LLVMRustLinkerAdd(
|
||||
|
@ -14,8 +14,7 @@ use snap::write::FrameEncoder;
|
||||
|
||||
use object::elf::NT_GNU_PROPERTY_TYPE_0;
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::owned_slice::try_slice_owned;
|
||||
use rustc_data_structures::sync::MetadataRef;
|
||||
use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
|
||||
use rustc_metadata::fs::METADATA_FILENAME;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_session::cstore::MetadataLoader;
|
||||
@ -39,7 +38,7 @@ pub struct DefaultMetadataLoader;
|
||||
fn load_metadata_with(
|
||||
path: &Path,
|
||||
f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>,
|
||||
) -> Result<MetadataRef, String> {
|
||||
) -> Result<OwnedSlice, String> {
|
||||
let file =
|
||||
File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?;
|
||||
|
||||
@ -49,7 +48,7 @@ fn load_metadata_with(
|
||||
}
|
||||
|
||||
impl MetadataLoader for DefaultMetadataLoader {
|
||||
fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
|
||||
fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> {
|
||||
load_metadata_with(path, |data| {
|
||||
let archive = object::read::archive::ArchiveFile::parse(&*data)
|
||||
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
|
||||
@ -69,7 +68,7 @@ impl MetadataLoader for DefaultMetadataLoader {
|
||||
})
|
||||
}
|
||||
|
||||
fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
|
||||
fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> {
|
||||
load_metadata_with(path, |data| search_for_section(path, data, ".rustc"))
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::any::Any;
|
||||
|
||||
use super::write::WriteBackendMethods;
|
||||
use super::CodegenObject;
|
||||
use crate::back::write::TargetMachineFactoryFn;
|
||||
@ -5,6 +7,7 @@ use crate::{CodegenResults, ModuleCodegen};
|
||||
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
@ -20,11 +23,6 @@ use rustc_span::symbol::Symbol;
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
use rustc_target::spec::Target;
|
||||
|
||||
pub use rustc_data_structures::sync::MetadataRef;
|
||||
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use std::any::Any;
|
||||
|
||||
pub trait BackendTypes {
|
||||
type Value: CodegenObject;
|
||||
type Function: CodegenObject;
|
||||
|
@ -3,7 +3,8 @@ use std::fmt;
|
||||
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_middle::mir::AssertKind;
|
||||
use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::{layout::LayoutError, ConstInt};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use super::InterpCx;
|
||||
@ -169,14 +170,14 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
||||
// See <https://github.com/rust-lang/rust/pull/63152>.
|
||||
let mut err = struct_error(tcx, &self.error.to_string());
|
||||
self.decorate(&mut err, decorate);
|
||||
ErrorHandled::Reported(err.emit())
|
||||
ErrorHandled::Reported(err.emit().into())
|
||||
}
|
||||
_ => {
|
||||
// Report as hard error.
|
||||
let mut err = struct_error(tcx, message);
|
||||
err.span_label(self.span, self.error.to_string());
|
||||
self.decorate(&mut err, decorate);
|
||||
ErrorHandled::Reported(err.emit())
|
||||
ErrorHandled::Reported(err.emit().into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -382,7 +382,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||
rustc_span::DUMMY_SP,
|
||||
"This is likely a const item that is missing from its impl",
|
||||
);
|
||||
throw_inval!(AlreadyReported(guar));
|
||||
throw_inval!(AlreadyReported(guar.into()));
|
||||
} else {
|
||||
// `find_mir_or_eval_fn` checks that this is a const fn before even calling us,
|
||||
// so this should be unreachable.
|
||||
|
@ -7,14 +7,13 @@ use either::{Either, Left, Right};
|
||||
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{ErrorHandled, InterpError};
|
||||
use rustc_middle::mir::interpret::{ErrorHandled, InterpError, ReportedErrorInfo};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::layout::{
|
||||
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
|
||||
TyAndLayout,
|
||||
};
|
||||
use rustc_middle::ty::{
|
||||
self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
|
||||
};
|
||||
use rustc_middle::ty::{self, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::Span;
|
||||
@ -470,7 +469,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
};
|
||||
// do not continue if typeck errors occurred (can only occur in local crate)
|
||||
if let Some(err) = body.tainted_by_errors {
|
||||
throw_inval!(AlreadyReported(err));
|
||||
throw_inval!(AlreadyReported(ReportedErrorInfo::tainted_by_errors(err)));
|
||||
}
|
||||
Ok(body)
|
||||
}
|
||||
@ -517,7 +516,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Ok(None) => throw_inval!(TooGeneric),
|
||||
|
||||
// FIXME(eddyb) this could be a bit more specific than `AlreadyReported`.
|
||||
Err(error_reported) => throw_inval!(AlreadyReported(error_reported)),
|
||||
Err(error_reported) => throw_inval!(AlreadyReported(error_reported.into())),
|
||||
}
|
||||
}
|
||||
|
||||
@ -905,7 +904,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| {
|
||||
match err {
|
||||
ErrorHandled::Reported(err) => {
|
||||
if let Some(span) = span {
|
||||
if !err.is_tainted_by_errors() && let Some(span) = span {
|
||||
// To make it easier to figure out where this error comes from, also add a note at the current location.
|
||||
self.tcx.sess.span_note_without_error(span, "erroneous constant used");
|
||||
}
|
||||
|
@ -595,7 +595,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// FIXME(generic_const_exprs): `ConstKind::Expr` should be able to be evaluated
|
||||
ty::ConstKind::Expr(_) => throw_inval!(TooGeneric),
|
||||
ty::ConstKind::Error(reported) => {
|
||||
throw_inval!(AlreadyReported(reported))
|
||||
throw_inval!(AlreadyReported(reported.into()))
|
||||
}
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
let instance = self.resolve(uv.def, uv.substs)?;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::{borrow::Borrow, ops::Deref};
|
||||
|
||||
use crate::sync::Lrc;
|
||||
// Use our fake Send/Sync traits when on not parallel compiler,
|
||||
// so that `OwnedSlice` only implements/requires Send/Sync
|
||||
// for parallel compiler builds.
|
||||
@ -7,7 +8,7 @@ use crate::sync::{Send, Sync};
|
||||
|
||||
/// An owned slice.
|
||||
///
|
||||
/// This is similar to `Box<[u8]>` but allows slicing and using anything as the
|
||||
/// This is similar to `Lrc<[u8]>` but allows slicing and using anything as the
|
||||
/// backing buffer.
|
||||
///
|
||||
/// See [`slice_owned`] for `OwnedSlice` construction and examples.
|
||||
@ -16,6 +17,7 @@ use crate::sync::{Send, Sync};
|
||||
///
|
||||
/// This is essentially a replacement for `owning_ref` which is a lot simpler
|
||||
/// and even sound! 🌸
|
||||
#[derive(Clone)]
|
||||
pub struct OwnedSlice {
|
||||
/// This is conceptually a `&'self.owner [u8]`.
|
||||
bytes: *const [u8],
|
||||
@ -31,7 +33,7 @@ pub struct OwnedSlice {
|
||||
// \/
|
||||
// ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770)
|
||||
#[expect(dead_code)]
|
||||
owner: Box<dyn Send + Sync>,
|
||||
owner: Lrc<dyn Send + Sync>,
|
||||
}
|
||||
|
||||
/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function.
|
||||
@ -72,10 +74,10 @@ where
|
||||
O: Send + Sync + 'static,
|
||||
F: FnOnce(&O) -> Result<&[u8], E>,
|
||||
{
|
||||
// We box the owner of the bytes, so it doesn't move.
|
||||
// We wrap the owner of the bytes in, so it doesn't move.
|
||||
//
|
||||
// Since the owner does not move and we don't access it in any way
|
||||
// before drop, there is nothing that can invalidate the bytes pointer.
|
||||
// before dropping, there is nothing that can invalidate the bytes pointer.
|
||||
//
|
||||
// Thus, "extending" the lifetime of the reference returned from `F` is fine.
|
||||
// We pretend that we pass it a reference that lives as long as the returned slice.
|
||||
@ -83,12 +85,39 @@ where
|
||||
// N.B. the HRTB on the `slicer` is important — without it the caller could provide
|
||||
// a short lived slice, unrelated to the owner.
|
||||
|
||||
let owner = Box::new(owner);
|
||||
let owner = Lrc::new(owner);
|
||||
let bytes = slicer(&*owner)?;
|
||||
|
||||
Ok(OwnedSlice { bytes, owner })
|
||||
}
|
||||
|
||||
impl OwnedSlice {
|
||||
/// Slice this slice by `slicer`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
|
||||
/// let vec = vec![1, 2, 3, 4];
|
||||
///
|
||||
/// // Identical to slicing via `&v[1..3]` but produces an owned slice
|
||||
/// let slice: OwnedSlice = slice_owned(vec, |v| &v[..]);
|
||||
/// assert_eq!(&*slice, [1, 2, 3, 4]);
|
||||
///
|
||||
/// let slice = slice.slice(|slice| &slice[1..][..2]);
|
||||
/// assert_eq!(&*slice, [2, 3]);
|
||||
/// ```
|
||||
///
|
||||
pub fn slice(self, slicer: impl FnOnce(&[u8]) -> &[u8]) -> OwnedSlice {
|
||||
// This is basically identical to `try_slice_owned`,
|
||||
// `slicer` can only return slices of its argument or some static data,
|
||||
// both of which are valid while `owner` is alive.
|
||||
|
||||
let bytes = slicer(&self);
|
||||
OwnedSlice { bytes, ..self }
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for OwnedSlice {
|
||||
type Target = [u8];
|
||||
|
||||
@ -108,11 +137,11 @@ impl Borrow<[u8]> for OwnedSlice {
|
||||
}
|
||||
}
|
||||
|
||||
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send`
|
||||
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send`
|
||||
#[cfg(parallel_compiler)]
|
||||
unsafe impl Send for OwnedSlice {}
|
||||
|
||||
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync`
|
||||
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync`
|
||||
#[cfg(parallel_compiler)]
|
||||
unsafe impl Sync for OwnedSlice {}
|
||||
|
||||
|
@ -26,7 +26,7 @@ fn static_storage() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slice_the_slice() {
|
||||
fn slice_owned_the_slice() {
|
||||
let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice);
|
||||
let slice = slice_owned(slice, |s| &s[1..][..4]);
|
||||
let slice = slice_owned(slice, |s| s);
|
||||
@ -35,6 +35,16 @@ fn slice_the_slice() {
|
||||
assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slice_the_slice() {
|
||||
let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice)
|
||||
.slice(|s| &s[1..][..4])
|
||||
.slice(|s| s)
|
||||
.slice(|s| &s[1..]);
|
||||
|
||||
assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_and_fail() {
|
||||
let res = try_slice_owned(vec![0], |v| v.get(12..).ok_or(()));
|
||||
|
@ -40,7 +40,6 @@
|
||||
//! [^2] `MTLockRef` is a typedef.
|
||||
|
||||
pub use crate::marker::*;
|
||||
use crate::owned_slice::OwnedSlice;
|
||||
use std::collections::HashMap;
|
||||
use std::hash::{BuildHasher, Hash};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
@ -92,6 +91,7 @@ mod mode {
|
||||
}
|
||||
|
||||
pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(not(parallel_compiler))] {
|
||||
pub unsafe auto trait Send {}
|
||||
@ -244,8 +244,6 @@ cfg_if! {
|
||||
r
|
||||
}
|
||||
|
||||
pub type MetadataRef = OwnedSlice;
|
||||
|
||||
pub use std::rc::Rc as Lrc;
|
||||
pub use std::rc::Weak as Weak;
|
||||
pub use std::cell::Ref as ReadGuard;
|
||||
@ -517,8 +515,6 @@ cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
pub type MetadataRef = OwnedSlice;
|
||||
|
||||
/// This makes locks panic if they are already held.
|
||||
/// It is only useful when you are running in a single thread
|
||||
const ERROR_CHECKING: bool = false;
|
||||
|
@ -478,6 +478,7 @@ pub enum StashKey {
|
||||
/// FRU syntax
|
||||
MaybeFruTypo,
|
||||
CallAssocMethod,
|
||||
TraitMissingMethod,
|
||||
}
|
||||
|
||||
fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
|
||||
|
@ -338,7 +338,7 @@ declare_features! (
|
||||
/// Allow conditional compilation depending on rust version
|
||||
(active, cfg_version, "1.45.0", Some(64796), None),
|
||||
/// Allows to use the `#[cfi_encoding = ""]` attribute.
|
||||
(active, cfi_encoding, "1.69.0", Some(89653), None),
|
||||
(active, cfi_encoding, "CURRENT_RUSTC_VERSION", Some(89653), None),
|
||||
/// Allows `for<...>` on closures and generators.
|
||||
(active, closure_lifetime_binder, "1.64.0", Some(97362), None),
|
||||
/// Allows `#[track_caller]` on closures and generators.
|
||||
|
@ -1,10 +0,0 @@
|
||||
use crate::LangItem;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub struct LangItemError(pub LangItem);
|
||||
|
||||
impl ToString for LangItemError {
|
||||
fn to_string(&self) -> String {
|
||||
format!("requires `{}` lang_item", self.0.name())
|
||||
}
|
||||
}
|
@ -8,7 +8,6 @@
|
||||
//! * Functions called by the compiler itself.
|
||||
|
||||
use crate::def_id::DefId;
|
||||
use crate::errors::LangItemError;
|
||||
use crate::{MethodKind, Target};
|
||||
|
||||
use rustc_ast as ast;
|
||||
@ -42,13 +41,6 @@ impl LanguageItems {
|
||||
self.items[item as usize] = Some(def_id);
|
||||
}
|
||||
|
||||
/// Requires that a given `LangItem` was bound and returns the corresponding `DefId`.
|
||||
/// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`,
|
||||
/// returns an error encapsulating the `LangItem`.
|
||||
pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> {
|
||||
self.get(it).ok_or_else(|| LangItemError(it))
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (LangItem, DefId)> + '_ {
|
||||
self.items
|
||||
.iter()
|
||||
|
@ -30,7 +30,6 @@ pub mod def;
|
||||
pub mod def_path_hash_map;
|
||||
pub mod definitions;
|
||||
pub mod diagnostic_items;
|
||||
pub mod errors;
|
||||
pub use rustc_span::def_id;
|
||||
mod hir;
|
||||
pub mod hir_id;
|
||||
|
@ -19,7 +19,7 @@ use rustc_ast::TraitObjectSyntax;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{
|
||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
|
||||
MultiSpan,
|
||||
MultiSpan, StashKey,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
||||
@ -38,7 +38,6 @@ use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}
|
||||
use rustc_middle::ty::{DynKind, ToPredicate};
|
||||
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||
use rustc_span::{sym, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
@ -3718,7 +3717,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
));
|
||||
}
|
||||
|
||||
if self_ty.span.edition() >= Edition::Edition2021 {
|
||||
if self_ty.span.edition().rust_2021() {
|
||||
let msg = "trait objects must include the `dyn` keyword";
|
||||
let label = "add `dyn` keyword before this trait";
|
||||
let mut diag =
|
||||
@ -3732,7 +3731,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
}
|
||||
// check if the impl trait that we are considering is a impl of a local trait
|
||||
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
|
||||
diag.emit();
|
||||
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
|
||||
} else {
|
||||
let msg = "trait objects without an explicit `dyn` are deprecated";
|
||||
tcx.struct_span_lint_hir(
|
||||
|
@ -1514,8 +1514,8 @@ fn opaque_type_cycle_error(
|
||||
}
|
||||
if tcx.sess.opts.unstable_opts.drop_tracking_mir
|
||||
&& let DefKind::Generator = tcx.def_kind(closure_def_id)
|
||||
&& let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id)
|
||||
{
|
||||
let generator_layout = tcx.mir_generator_witnesses(closure_def_id);
|
||||
for interior_ty in &generator_layout.field_tys {
|
||||
label_match(interior_ty.ty, interior_ty.source_info.span);
|
||||
}
|
||||
|
@ -298,9 +298,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
|
||||
|
||||
let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
|
||||
|
||||
let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| {
|
||||
tcx.sess.fatal(format!("`CoerceUnsized` implementation {}", err.to_string()));
|
||||
});
|
||||
let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
|
||||
|
||||
let source = tcx.type_of(impl_did).subst_identity();
|
||||
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
|
||||
|
@ -79,3 +79,14 @@ hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but
|
||||
hir_typeck_suggest_boxing_note = for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
|
||||
|
||||
hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `Box::new`
|
||||
|
||||
hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method ->
|
||||
[true] {""}
|
||||
*[other] {" "}in the current scope
|
||||
}
|
||||
|
||||
hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty ->
|
||||
[NONE] {""}
|
||||
[implement] , perhaps you need to implement it
|
||||
*[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
//! Errors emitted by `rustc_hir_typeck`.
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
@ -295,3 +297,25 @@ pub enum SuggestBoxing {
|
||||
end: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_no_associated_item, code = "E0599")]
|
||||
pub struct NoAssociatedItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub item_kind: &'static str,
|
||||
pub item_name: Ident,
|
||||
pub ty_prefix: Cow<'static, str>,
|
||||
pub ty_str: String,
|
||||
pub trait_missing_method: bool,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(hir_typeck_candidate_trait_note)]
|
||||
pub struct CandidateTraitNote {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub trait_name: String,
|
||||
pub item_name: Ident,
|
||||
pub action_or_ty: String,
|
||||
}
|
||||
|
@ -1245,6 +1245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
error,
|
||||
Some((rcvr, args)),
|
||||
expected,
|
||||
false,
|
||||
) {
|
||||
err.emit();
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use crate::rvalue_scopes;
|
||||
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
|
||||
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -853,6 +853,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let item_name = item_segment.ident;
|
||||
let result = self
|
||||
.resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
|
||||
.and_then(|r| {
|
||||
// lint bare trait if the method is found in the trait
|
||||
if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
|
||||
diag.emit();
|
||||
}
|
||||
Ok(r)
|
||||
})
|
||||
.or_else(|error| {
|
||||
let guar = self
|
||||
.tcx
|
||||
@ -863,17 +870,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
_ => Err(guar),
|
||||
};
|
||||
|
||||
let trait_missing_method =
|
||||
matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait();
|
||||
// If we have a path like `MyTrait::missing_method`, then don't register
|
||||
// a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise,
|
||||
// register a WF obligation so that we can detect any additional
|
||||
// errors in the self type.
|
||||
if !(matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait()) {
|
||||
if !trait_missing_method {
|
||||
self.register_wf_obligation(
|
||||
ty.raw.into(),
|
||||
qself.span,
|
||||
traits::WellFormed(None),
|
||||
);
|
||||
}
|
||||
|
||||
// emit or cancel the diagnostic for bare traits
|
||||
if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
|
||||
if trait_missing_method {
|
||||
// cancel the diag for bare traits when meeting `MyTrait::missing_method`
|
||||
diag.cancel();
|
||||
} else {
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
|
||||
if item_name.name != kw::Empty {
|
||||
if let Some(mut e) = self.report_method_error(
|
||||
span,
|
||||
@ -883,10 +903,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
error,
|
||||
None,
|
||||
Expectation::NoExpectation,
|
||||
trait_missing_method && span.edition().rust_2021(), // emits missing method for trait only after edition 2021
|
||||
) {
|
||||
e.emit();
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
});
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
//! found or is otherwise invalid.
|
||||
|
||||
use crate::errors;
|
||||
use crate::errors::CandidateTraitNote;
|
||||
use crate::errors::NoAssociatedItem;
|
||||
use crate::Expectation;
|
||||
use crate::FnCtxt;
|
||||
use rustc_ast::ast::Mutability;
|
||||
@ -38,6 +40,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _
|
||||
use rustc_trait_selection::traits::{
|
||||
FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
|
||||
use super::{CandidateSource, MethodError, NoMatchData};
|
||||
@ -112,6 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
error: MethodError<'tcx>,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||
expected: Expectation<'tcx>,
|
||||
trait_missing_method: bool,
|
||||
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
|
||||
// Avoid suggestions when we don't know what's going on.
|
||||
if rcvr_ty.references_error() {
|
||||
@ -136,6 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
sugg_span,
|
||||
&mut no_match_data,
|
||||
expected,
|
||||
trait_missing_method,
|
||||
);
|
||||
}
|
||||
|
||||
@ -278,6 +283,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
sugg_span: Span,
|
||||
no_match_data: &mut NoMatchData<'tcx>,
|
||||
expected: Expectation<'tcx>,
|
||||
trait_missing_method: bool,
|
||||
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
|
||||
let mode = no_match_data.mode;
|
||||
let tcx = self.tcx;
|
||||
@ -323,7 +329,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span = item_name.span;
|
||||
|
||||
// Don't show generic arguments when the method can't be found in any implementation (#81576).
|
||||
let mut ty_str_reported = ty_str.clone();
|
||||
let mut ty_str_reported = if trait_missing_method {
|
||||
ty_str.strip_prefix("dyn ").expect("Failed to remove the prefix dyn").to_owned()
|
||||
} else {
|
||||
ty_str.clone()
|
||||
};
|
||||
|
||||
if let ty::Adt(_, generics) = rcvr_ty.kind() {
|
||||
if generics.len() > 0 {
|
||||
let mut autoderef = self.autoderef(span, rcvr_ty);
|
||||
@ -355,25 +366,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
{
|
||||
self.suggest_missing_writer(rcvr_ty, args)
|
||||
} else {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
tcx.sess.create_err(NoAssociatedItem {
|
||||
span,
|
||||
E0599,
|
||||
"no {} named `{}` found for {} `{}` in the current scope",
|
||||
item_kind,
|
||||
item_name,
|
||||
rcvr_ty.prefix_string(self.tcx),
|
||||
ty_str_reported,
|
||||
)
|
||||
ty_prefix: if trait_missing_method {
|
||||
// FIXME(mu001999) E0599 maybe not suitable here because it is for types
|
||||
Cow::from("trait")
|
||||
} else {
|
||||
rcvr_ty.prefix_string(self.tcx)
|
||||
},
|
||||
ty_str: ty_str_reported,
|
||||
trait_missing_method,
|
||||
})
|
||||
};
|
||||
if tcx.sess.source_map().is_multiline(sugg_span) {
|
||||
err.span_label(sugg_span.with_hi(span.lo()), "");
|
||||
}
|
||||
let ty_str = if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
|
||||
let mut ty_str = if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
|
||||
short_ty_str
|
||||
} else {
|
||||
ty_str
|
||||
};
|
||||
if trait_missing_method {
|
||||
ty_str =
|
||||
ty_str.strip_prefix("dyn ").expect("Failed to remove the prefix dyn").to_owned();
|
||||
}
|
||||
|
||||
if let Some(file) = ty_file {
|
||||
err.note(format!("the full type name has been written to '{}'", file.display(),));
|
||||
}
|
||||
@ -1067,6 +1086,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&static_candidates,
|
||||
unsatisfied_bounds,
|
||||
expected.only_has_type(self),
|
||||
trait_missing_method,
|
||||
);
|
||||
}
|
||||
|
||||
@ -2375,6 +2395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
static_candidates: &[CandidateSource],
|
||||
unsatisfied_bounds: bool,
|
||||
return_type: Option<Ty<'tcx>>,
|
||||
trait_missing_method: bool,
|
||||
) {
|
||||
let mut alt_rcvr_sugg = false;
|
||||
if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
|
||||
@ -2598,11 +2619,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
err.help(if param_type.is_some() {
|
||||
"items from traits can only be used if the type parameter is bounded by the trait"
|
||||
} else {
|
||||
"items from traits can only be used if the trait is implemented and in scope"
|
||||
});
|
||||
if !trait_missing_method {
|
||||
err.help(if param_type.is_some() {
|
||||
"items from traits can only be used if the type parameter is bounded by the trait"
|
||||
} else {
|
||||
"items from traits can only be used if the trait is implemented and in scope"
|
||||
});
|
||||
}
|
||||
|
||||
let candidates_len = candidates.len();
|
||||
let message = |action| {
|
||||
format!(
|
||||
@ -2633,47 +2657,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
Nothing,
|
||||
}
|
||||
let ast_generics = hir.get_generics(id.owner.def_id).unwrap();
|
||||
let (sp, mut introducer) = if let Some(span) =
|
||||
ast_generics.bounds_span_for_suggestions(def_id)
|
||||
{
|
||||
(span, Introducer::Plus)
|
||||
} else if let Some(colon_span) = param.colon_span {
|
||||
(colon_span.shrink_to_hi(), Introducer::Nothing)
|
||||
} else {
|
||||
(param.span.shrink_to_hi(), Introducer::Colon)
|
||||
};
|
||||
if matches!(
|
||||
param.kind,
|
||||
hir::GenericParamKind::Type { synthetic: true, .. },
|
||||
) {
|
||||
introducer = Introducer::Plus
|
||||
}
|
||||
let trait_def_ids: FxHashSet<DefId> = ast_generics
|
||||
.bounds_for_param(def_id)
|
||||
.flat_map(|bp| bp.bounds.iter())
|
||||
.filter_map(|bound| bound.trait_ref()?.trait_def_id())
|
||||
.collect();
|
||||
if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
|
||||
err.span_suggestions(
|
||||
sp,
|
||||
message(format!(
|
||||
"restrict type parameter `{}` with",
|
||||
param.name.ident(),
|
||||
)),
|
||||
if candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
|
||||
return;
|
||||
}
|
||||
let msg = message(format!(
|
||||
"restrict type parameter `{}` with",
|
||||
param.name.ident(),
|
||||
));
|
||||
let bounds_span = ast_generics.bounds_span_for_suggestions(def_id);
|
||||
if rcvr_ty.is_ref() && param.is_impl_trait() && bounds_span.is_some() {
|
||||
err.multipart_suggestions(
|
||||
msg,
|
||||
candidates.iter().map(|t| {
|
||||
format!(
|
||||
"{} {}",
|
||||
match introducer {
|
||||
Introducer::Plus => " +",
|
||||
Introducer::Colon => ":",
|
||||
Introducer::Nothing => "",
|
||||
},
|
||||
self.tcx.def_path_str(t.def_id),
|
||||
)
|
||||
vec![
|
||||
(param.span.shrink_to_lo(), "(".to_string()),
|
||||
(
|
||||
bounds_span.unwrap(),
|
||||
format!(" + {})", self.tcx.def_path_str(t.def_id)),
|
||||
),
|
||||
]
|
||||
}),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let (sp, introducer) = if let Some(span) = bounds_span {
|
||||
(span, Introducer::Plus)
|
||||
} else if let Some(colon_span) = param.colon_span {
|
||||
(colon_span.shrink_to_hi(), Introducer::Nothing)
|
||||
} else if param.is_impl_trait() {
|
||||
(param.span.shrink_to_hi(), Introducer::Plus)
|
||||
} else {
|
||||
(param.span.shrink_to_hi(), Introducer::Colon)
|
||||
};
|
||||
|
||||
err.span_suggestions(
|
||||
sp,
|
||||
msg,
|
||||
candidates.iter().map(|t| {
|
||||
format!(
|
||||
"{} {}",
|
||||
match introducer {
|
||||
Introducer::Plus => " +",
|
||||
Introducer::Colon => ":",
|
||||
Introducer::Nothing => "",
|
||||
},
|
||||
self.tcx.def_path_str(t.def_id)
|
||||
)
|
||||
}),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return;
|
||||
}
|
||||
Node::Item(hir::Item {
|
||||
@ -2736,27 +2775,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
(candidates, Vec::new())
|
||||
};
|
||||
|
||||
let action = if let Some(param) = param_type {
|
||||
format!("restrict type parameter `{}` with", param)
|
||||
} else {
|
||||
// FIXME: it might only need to be imported into scope, not implemented.
|
||||
"implement".to_string()
|
||||
};
|
||||
match &potential_candidates[..] {
|
||||
[] => {}
|
||||
[trait_info] if trait_info.def_id.is_local() => {
|
||||
err.span_note(
|
||||
self.tcx.def_span(trait_info.def_id),
|
||||
format!(
|
||||
"`{}` defines an item `{}`, perhaps you need to {} it",
|
||||
self.tcx.def_path_str(trait_info.def_id),
|
||||
item_name,
|
||||
action
|
||||
),
|
||||
);
|
||||
err.subdiagnostic(CandidateTraitNote {
|
||||
span: self.tcx.def_span(trait_info.def_id),
|
||||
trait_name: self.tcx.def_path_str(trait_info.def_id),
|
||||
item_name,
|
||||
action_or_ty: if trait_missing_method {
|
||||
"NONE".to_string()
|
||||
} else {
|
||||
param_type.map_or_else(
|
||||
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
|
||||
ToString::to_string,
|
||||
)
|
||||
},
|
||||
});
|
||||
}
|
||||
trait_infos => {
|
||||
let mut msg = message(action);
|
||||
let mut msg = message(param_type.map_or_else(
|
||||
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
|
||||
|param| format!("restrict type parameter `{}` with", param),
|
||||
));
|
||||
for (i, trait_info) in trait_infos.iter().enumerate() {
|
||||
msg.push_str(&format!(
|
||||
"\ncandidate #{}: `{}`",
|
||||
|
@ -1534,7 +1534,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? {
|
||||
let ct = tcx.expand_abstract_consts(ct.subst(tcx, substs));
|
||||
if let Err(e) = ct.error_reported() {
|
||||
return Err(ErrorHandled::Reported(e));
|
||||
return Err(ErrorHandled::Reported(e.into()));
|
||||
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
|
||||
return Err(ErrorHandled::TooGeneric);
|
||||
} else {
|
||||
|
@ -691,6 +691,8 @@ pub fn create_global_ctxt<'tcx>(
|
||||
callback(sess, &mut local_providers, &mut extern_providers);
|
||||
}
|
||||
|
||||
let incremental = dep_graph.is_fully_enabled();
|
||||
|
||||
sess.time("setup_global_ctxt", || {
|
||||
gcx_cell.get_or_init(move || {
|
||||
TyCtxt::create_global_ctxt(
|
||||
@ -705,6 +707,7 @@ pub fn create_global_ctxt<'tcx>(
|
||||
local_providers,
|
||||
extern_providers,
|
||||
query_result_on_disk_cache,
|
||||
incremental,
|
||||
),
|
||||
)
|
||||
})
|
||||
|
@ -611,7 +611,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
||||
|
||||
declare_lint! {
|
||||
/// The `missing_copy_implementations` lint detects potentially-forgotten
|
||||
/// implementations of [`Copy`].
|
||||
/// implementations of [`Copy`] for public types.
|
||||
///
|
||||
/// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
|
||||
///
|
||||
@ -729,7 +729,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
|
||||
|
||||
declare_lint! {
|
||||
/// The `missing_debug_implementations` lint detects missing
|
||||
/// implementations of [`fmt::Debug`].
|
||||
/// implementations of [`fmt::Debug`] for public types.
|
||||
///
|
||||
/// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
|
||||
///
|
||||
|
@ -1463,63 +1463,6 @@ LLVMRustGetBitcodeSliceFromObjectData(const char *data,
|
||||
return BitcodeOrError->getBufferStart();
|
||||
}
|
||||
|
||||
// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See
|
||||
// the comment in `back/lto.rs` for why this exists.
|
||||
extern "C" void
|
||||
LLVMRustThinLTOGetDICompileUnit(LLVMModuleRef Mod,
|
||||
DICompileUnit **A,
|
||||
DICompileUnit **B) {
|
||||
Module *M = unwrap(Mod);
|
||||
DICompileUnit **Cur = A;
|
||||
DICompileUnit **Next = B;
|
||||
for (DICompileUnit *CU : M->debug_compile_units()) {
|
||||
*Cur = CU;
|
||||
Cur = Next;
|
||||
Next = nullptr;
|
||||
if (Cur == nullptr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See
|
||||
// the comment in `back/lto.rs` for why this exists.
|
||||
extern "C" void
|
||||
LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) {
|
||||
Module *M = unwrap(Mod);
|
||||
|
||||
// If the original source module didn't have a `DICompileUnit` then try to
|
||||
// merge all the existing compile units. If there aren't actually any though
|
||||
// then there's not much for us to do so return.
|
||||
if (Unit == nullptr) {
|
||||
for (DICompileUnit *CU : M->debug_compile_units()) {
|
||||
Unit = CU;
|
||||
break;
|
||||
}
|
||||
if (Unit == nullptr)
|
||||
return;
|
||||
}
|
||||
|
||||
// Use LLVM's built-in `DebugInfoFinder` to find a bunch of debuginfo and
|
||||
// process it recursively. Note that we used to specifically iterate over
|
||||
// instructions to ensure we feed everything into it, but `processModule`
|
||||
// started doing this the same way in LLVM 7 (commit d769eb36ab2b8).
|
||||
DebugInfoFinder Finder;
|
||||
Finder.processModule(*M);
|
||||
|
||||
// After we've found all our debuginfo, rewrite all subprograms to point to
|
||||
// the same `DICompileUnit`.
|
||||
for (auto &F : Finder.subprograms()) {
|
||||
F->replaceUnit(Unit);
|
||||
}
|
||||
|
||||
// Erase any other references to other `DICompileUnit` instances, the verifier
|
||||
// will later ensure that we don't actually have any other stale references to
|
||||
// worry about.
|
||||
auto *MD = M->getNamedMetadata("llvm.dbg.cu");
|
||||
MD->clearOperands();
|
||||
MD->addOperand(Unit);
|
||||
}
|
||||
|
||||
// Computes the LTO cache key for the provided 'ModId' in the given 'Data',
|
||||
// storing the result in 'KeyOut'.
|
||||
// Currently, this cache key is a SHA-1 hash of anything that could affect
|
||||
|
@ -220,7 +220,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::owned_slice::slice_owned;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::sync::MetadataRef;
|
||||
use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg};
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use rustc_session::config::{self, CrateType};
|
||||
@ -782,7 +781,7 @@ fn get_metadata_section<'p>(
|
||||
if !filename.exists() {
|
||||
return Err(MetadataError::NotPresent(filename));
|
||||
}
|
||||
let raw_bytes: MetadataRef = match flavor {
|
||||
let raw_bytes = match flavor {
|
||||
CrateFlavor::Rlib => {
|
||||
loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)?
|
||||
}
|
||||
@ -843,7 +842,7 @@ fn get_metadata_section<'p>(
|
||||
slice_owned(mmap, Deref::deref)
|
||||
}
|
||||
};
|
||||
let blob = MetadataBlob::new(raw_bytes);
|
||||
let blob = MetadataBlob(raw_bytes);
|
||||
if blob.is_compatible() {
|
||||
Ok(blob)
|
||||
} else {
|
||||
|
@ -7,6 +7,7 @@ use crate::rmeta::*;
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::owned_slice::OwnedSlice;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc, OnceCell};
|
||||
use rustc_data_structures::unhash::UnhashMap;
|
||||
@ -50,7 +51,7 @@ mod cstore_impl;
|
||||
/// A `MetadataBlob` internally is just a reference counted pointer to
|
||||
/// the actual data, so cloning it is cheap.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct MetadataBlob(Lrc<MetadataRef>);
|
||||
pub(crate) struct MetadataBlob(pub(crate) OwnedSlice);
|
||||
|
||||
impl std::ops::Deref for MetadataBlob {
|
||||
type Target = [u8];
|
||||
@ -660,10 +661,6 @@ impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T>
|
||||
implement_ty_decoder!(DecodeContext<'a, 'tcx>);
|
||||
|
||||
impl MetadataBlob {
|
||||
pub(crate) fn new(metadata_ref: MetadataRef) -> MetadataBlob {
|
||||
MetadataBlob(Lrc::new(metadata_ref))
|
||||
}
|
||||
|
||||
pub(crate) fn is_compatible(&self) -> bool {
|
||||
self.blob().starts_with(METADATA_HEADER)
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::rmeta::DecodeContext;
|
||||
use crate::rmeta::EncodeContext;
|
||||
use rustc_data_structures::owned_slice::slice_owned;
|
||||
use rustc_data_structures::owned_slice::OwnedSlice;
|
||||
use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap};
|
||||
use rustc_middle::parameterized_over_tcx;
|
||||
@ -47,7 +46,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static>
|
||||
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> {
|
||||
let len = d.read_usize();
|
||||
let pos = d.position();
|
||||
let o = slice_owned(d.blob().clone(), |blob| &blob[pos..pos + len]);
|
||||
let o = d.blob().clone().0.slice(|blob| &blob[pos..pos + len]);
|
||||
|
||||
// Although we already have the data we need via the `OwnedSlice`, we still need
|
||||
// to advance the `DecodeContext`'s position so it's in a valid state after
|
||||
|
@ -1516,8 +1516,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
if encode_opt {
|
||||
record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id));
|
||||
|
||||
if tcx.sess.opts.unstable_opts.drop_tracking_mir && let DefKind::Generator = self.tcx.def_kind(def_id) {
|
||||
record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- tcx.mir_generator_witnesses(def_id));
|
||||
if tcx.sess.opts.unstable_opts.drop_tracking_mir
|
||||
&& let DefKind::Generator = self.tcx.def_kind(def_id)
|
||||
&& let Some(witnesses) = tcx.mir_generator_witnesses(def_id)
|
||||
{
|
||||
record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- witnesses);
|
||||
}
|
||||
}
|
||||
if encode_const {
|
||||
|
@ -7,7 +7,6 @@ use table::TableBuilder;
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::sync::MetadataRef;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
|
||||
|
@ -39,5 +39,7 @@ middle_strict_coherence_needs_negative_coherence =
|
||||
to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
|
||||
.label = due to this attribute
|
||||
|
||||
middle_requires_lang_item = requires `{$name}` lang_item
|
||||
|
||||
middle_const_not_used_in_type_alias =
|
||||
const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias
|
||||
|
@ -1,5 +1,5 @@
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::ty::Ty;
|
||||
|
||||
@ -73,6 +73,14 @@ pub(crate) struct StrictCoherenceNeedsNegativeCoherence {
|
||||
pub attr_span: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_requires_lang_item)]
|
||||
pub(crate) struct RequiresLangItem {
|
||||
#[primary_span]
|
||||
pub span: Option<Span>,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_const_not_used_in_type_alias)]
|
||||
pub(super) struct ConstNotUsedTraitAlias {
|
||||
|
@ -95,7 +95,6 @@ pub mod middle;
|
||||
pub mod mir;
|
||||
pub mod thir;
|
||||
pub mod traits;
|
||||
#[macro_use]
|
||||
pub mod ty;
|
||||
pub mod util;
|
||||
mod values;
|
||||
|
@ -18,12 +18,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Returns the `DefId` for a given `LangItem`.
|
||||
/// If not found, fatally aborts compilation.
|
||||
pub fn require_lang_item(self, lang_item: LangItem, span: Option<Span>) -> DefId {
|
||||
self.lang_items().require(lang_item).unwrap_or_else(|err| {
|
||||
if let Some(span) = span {
|
||||
self.sess.span_fatal(span, err.to_string())
|
||||
} else {
|
||||
self.sess.fatal(err.to_string())
|
||||
}
|
||||
self.lang_items().get(lang_item).unwrap_or_else(|| {
|
||||
self.sess.emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() });
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
|
||||
|
||||
use crate::mir::interpret::ConstValue;
|
||||
use crate::ty::{layout, query::TyCtxtAt, tls, Ty, ValTree};
|
||||
use crate::query::TyCtxtAt;
|
||||
use crate::ty::{layout, tls, Ty, ValTree};
|
||||
|
||||
use rustc_data_structures::sync::Lock;
|
||||
use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
|
||||
@ -15,15 +16,49 @@ use std::{any::Any, backtrace::Backtrace, fmt};
|
||||
pub enum ErrorHandled {
|
||||
/// Already reported an error for this evaluation, and the compilation is
|
||||
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
|
||||
Reported(ErrorGuaranteed),
|
||||
Reported(ReportedErrorInfo),
|
||||
/// Don't emit an error, the evaluation failed because the MIR was generic
|
||||
/// and the substs didn't fully monomorphize it.
|
||||
TooGeneric,
|
||||
}
|
||||
|
||||
impl From<ErrorGuaranteed> for ErrorHandled {
|
||||
fn from(err: ErrorGuaranteed) -> ErrorHandled {
|
||||
ErrorHandled::Reported(err)
|
||||
#[inline]
|
||||
fn from(error: ErrorGuaranteed) -> ErrorHandled {
|
||||
ErrorHandled::Reported(error.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
||||
pub struct ReportedErrorInfo {
|
||||
error: ErrorGuaranteed,
|
||||
is_tainted_by_errors: bool,
|
||||
}
|
||||
|
||||
impl ReportedErrorInfo {
|
||||
#[inline]
|
||||
pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo {
|
||||
ReportedErrorInfo { is_tainted_by_errors: true, error }
|
||||
}
|
||||
|
||||
/// Returns true if evaluation failed because MIR was tainted by errors.
|
||||
#[inline]
|
||||
pub fn is_tainted_by_errors(self) -> bool {
|
||||
self.is_tainted_by_errors
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorGuaranteed> for ReportedErrorInfo {
|
||||
#[inline]
|
||||
fn from(error: ErrorGuaranteed) -> ReportedErrorInfo {
|
||||
ReportedErrorInfo { is_tainted_by_errors: false, error }
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ErrorGuaranteed> for ReportedErrorInfo {
|
||||
#[inline]
|
||||
fn into(self) -> ErrorGuaranteed {
|
||||
self.error
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +124,7 @@ fn print_backtrace(backtrace: &Backtrace) {
|
||||
|
||||
impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
|
||||
fn from(err: ErrorGuaranteed) -> Self {
|
||||
InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into()
|
||||
InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into()
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +160,7 @@ pub enum InvalidProgramInfo<'tcx> {
|
||||
/// Resolution can fail if we are in a too generic context.
|
||||
TooGeneric,
|
||||
/// Abort in case errors are already reported.
|
||||
AlreadyReported(ErrorGuaranteed),
|
||||
AlreadyReported(ReportedErrorInfo),
|
||||
/// An error occurred during layout computation.
|
||||
Layout(layout::LayoutError<'tcx>),
|
||||
/// An error occurred during FnAbi computation: the passed --target lacks FFI support
|
||||
@ -144,7 +179,7 @@ impl fmt::Display for InvalidProgramInfo<'_> {
|
||||
use InvalidProgramInfo::*;
|
||||
match self {
|
||||
TooGeneric => write!(f, "encountered overly generic constant"),
|
||||
AlreadyReported(ErrorGuaranteed { .. }) => {
|
||||
AlreadyReported(_) => {
|
||||
write!(
|
||||
f,
|
||||
"an error has already been reported elsewhere (this should not usually be printed)"
|
||||
|
@ -120,8 +120,8 @@ use crate::ty::{self, Instance, Ty, TyCtxt};
|
||||
pub use self::error::{
|
||||
struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
|
||||
EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo,
|
||||
MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo,
|
||||
UninitBytesAccess, UnsupportedOpInfo,
|
||||
MachineStopType, ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch,
|
||||
UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
|
||||
};
|
||||
|
||||
pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar};
|
||||
|
@ -1,9 +1,10 @@
|
||||
use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId};
|
||||
|
||||
use crate::mir;
|
||||
use crate::query::{TyCtxtAt, TyCtxtEnsure};
|
||||
use crate::ty::subst::InternalSubsts;
|
||||
use crate::ty::visit::TypeVisitableExt;
|
||||
use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt};
|
||||
use crate::ty::{self, TyCtxt};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_session::lint;
|
||||
@ -61,7 +62,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
self.const_eval_global_id(param_env, cid, span)
|
||||
}
|
||||
Ok(None) => Err(ErrorHandled::TooGeneric),
|
||||
Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
|
||||
Err(err) => Err(ErrorHandled::Reported(err.into())),
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +111,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
})
|
||||
}
|
||||
Ok(None) => Err(ErrorHandled::TooGeneric),
|
||||
Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
|
||||
Err(err) => Err(ErrorHandled::Reported(err.into())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2342,7 +2342,7 @@ impl<'tcx> ConstantKind<'tcx> {
|
||||
match tcx.const_eval_resolve(param_env, uneval, None) {
|
||||
Ok(val) => Self::Val(val, ty),
|
||||
Err(ErrorHandled::TooGeneric) => self,
|
||||
Err(ErrorHandled::Reported(guar)) => Self::Ty(tcx.const_error(ty, guar)),
|
||||
Err(ErrorHandled::Reported(guar)) => Self::Ty(tcx.const_error(ty, guar.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ use crate::mir::interpret::{
|
||||
use crate::mir::interpret::{LitToConstError, LitToConstInput};
|
||||
use crate::mir::mono::CodegenUnit;
|
||||
use crate::query::erase::{erase, restore, Erase};
|
||||
use crate::query::plumbing::{query_ensure, query_get_at, DynamicQuery};
|
||||
use crate::thir;
|
||||
use crate::traits::query::{
|
||||
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
|
||||
@ -39,10 +40,6 @@ use crate::traits::specialization_graph;
|
||||
use crate::traits::{self, ImplSource};
|
||||
use crate::ty::fast_reject::SimplifiedType;
|
||||
use crate::ty::layout::ValidityRequirement;
|
||||
use crate::ty::query::{
|
||||
query_ensure, query_get_at, DynamicQuery, IntoQueryParam, TyCtxtAt, TyCtxtEnsure,
|
||||
TyCtxtEnsureWithValue,
|
||||
};
|
||||
use crate::ty::subst::{GenericArg, SubstsRef};
|
||||
use crate::ty::util::AlwaysRequiresDrop;
|
||||
use crate::ty::GeneratorDiagnosticData;
|
||||
@ -90,8 +87,11 @@ use std::sync::Arc;
|
||||
|
||||
pub mod erase;
|
||||
mod keys;
|
||||
pub mod on_disk_cache;
|
||||
pub use keys::{AsLocalKey, Key, LocalCrate};
|
||||
pub mod on_disk_cache;
|
||||
#[macro_use]
|
||||
pub mod plumbing;
|
||||
pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue};
|
||||
|
||||
// Each of these queries corresponds to a function pointer field in the
|
||||
// `Providers` struct for requesting a value of that type, and a method
|
||||
@ -527,7 +527,7 @@ rustc_queries! {
|
||||
}
|
||||
}
|
||||
|
||||
query mir_generator_witnesses(key: DefId) -> &'tcx mir::GeneratorLayout<'tcx> {
|
||||
query mir_generator_witnesses(key: DefId) -> &'tcx Option<mir::GeneratorLayout<'tcx>> {
|
||||
arena_cache
|
||||
desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
|
@ -6,7 +6,6 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_macros::HashStable;
|
||||
use std::fmt;
|
||||
|
||||
mod int;
|
||||
mod kind;
|
||||
@ -21,15 +20,6 @@ pub use valtree::*;
|
||||
#[rustc_pass_by_value]
|
||||
pub struct Const<'tcx>(pub(super) Interned<'tcx, ConstData<'tcx>>);
|
||||
|
||||
impl<'tcx> fmt::Debug for Const<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// This reflects what `Const` looked liked before `Interned` was
|
||||
// introduced. We print it like this to avoid having to update expected
|
||||
// output in a lot of tests.
|
||||
write!(f, "Const {{ ty: {:?}, kind: {:?} }}", self.ty(), self.kind())
|
||||
}
|
||||
}
|
||||
|
||||
/// Typed constant value.
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
|
||||
pub struct ConstData<'tcx> {
|
||||
|
@ -42,7 +42,7 @@ impl<'tcx> UnevaluatedConst<'tcx> {
|
||||
}
|
||||
|
||||
/// Represents a constant in Rust.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
#[derive(derive_more::From)]
|
||||
pub enum ConstKind<'tcx> {
|
||||
@ -128,7 +128,7 @@ impl<'tcx> ConstKind<'tcx> {
|
||||
}
|
||||
|
||||
/// An inference variable for a const, for use in const generics.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
|
||||
pub enum InferConst<'tcx> {
|
||||
/// Infer the value of the const.
|
||||
Var(ty::ConstVid<'tcx>),
|
||||
@ -245,7 +245,7 @@ impl<'tcx> ConstKind<'tcx> {
|
||||
// can leak through `val` into the const we return.
|
||||
Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
|
||||
Err(ErrorHandled::TooGeneric) => None,
|
||||
Err(ErrorHandled::Reported(e)) => Some(Err(e)),
|
||||
Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
|
||||
}
|
||||
}
|
||||
EvalMode::Mir => {
|
||||
@ -256,7 +256,7 @@ impl<'tcx> ConstKind<'tcx> {
|
||||
// can leak through `val` into the const we return.
|
||||
Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
|
||||
Err(ErrorHandled::TooGeneric) => None,
|
||||
Err(ErrorHandled::Reported(e)) => Some(Err(e)),
|
||||
Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,14 +14,14 @@ use crate::middle::resolve_bound_vars;
|
||||
use crate::middle::stability;
|
||||
use crate::mir::interpret::{self, Allocation, ConstAllocation};
|
||||
use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted};
|
||||
use crate::query::plumbing::QuerySystem;
|
||||
use crate::query::LocalCrate;
|
||||
use crate::query::Providers;
|
||||
use crate::query::{IntoQueryParam, TyCtxtAt};
|
||||
use crate::thir::Thir;
|
||||
use crate::traits;
|
||||
use crate::traits::solve;
|
||||
use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData};
|
||||
use crate::ty::query::QuerySystem;
|
||||
use crate::ty::query::{self, TyCtxtAt};
|
||||
use crate::ty::{
|
||||
self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid,
|
||||
GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
|
||||
@ -80,8 +80,6 @@ use std::iter;
|
||||
use std::mem;
|
||||
use std::ops::{Bound, Deref};
|
||||
|
||||
use super::query::IntoQueryParam;
|
||||
|
||||
const TINY_CONST_EVAL_LIMIT: Limit = Limit(20);
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
@ -512,7 +510,7 @@ pub struct GlobalCtxt<'tcx> {
|
||||
|
||||
untracked: Untracked,
|
||||
|
||||
pub query_system: query::QuerySystem<'tcx>,
|
||||
pub query_system: QuerySystem<'tcx>,
|
||||
pub(crate) query_kinds: &'tcx [DepKindStruct<'tcx>],
|
||||
|
||||
// Internal caches for metadata decoding. No need to track deps on this.
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::{GlobalCtxt, TyCtxt};
|
||||
|
||||
use crate::dep_graph::TaskDepsRef;
|
||||
use crate::ty::query;
|
||||
use crate::query::plumbing::QueryJobId;
|
||||
use rustc_data_structures::sync::{self, Lock};
|
||||
use rustc_errors::Diagnostic;
|
||||
#[cfg(not(parallel_compiler))]
|
||||
@ -22,7 +22,7 @@ pub struct ImplicitCtxt<'a, 'tcx> {
|
||||
|
||||
/// The current query job, if any. This is updated by `JobOwner::start` in
|
||||
/// `ty::query::plumbing` when executing a query.
|
||||
pub query: Option<query::QueryJobId>,
|
||||
pub query: Option<QueryJobId>,
|
||||
|
||||
/// Where to store diagnostics for the current query job, if any.
|
||||
/// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use crate::query::TyCtxtAt;
|
||||
use crate::ty::normalize_erasing_regions::NormalizationError;
|
||||
use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic};
|
||||
@ -543,20 +544,20 @@ impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> {
|
||||
impl<'tcx> HasDataLayout for TyCtxtAt<'tcx> {
|
||||
#[inline]
|
||||
fn data_layout(&self) -> &TargetDataLayout {
|
||||
&self.data_layout
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> {
|
||||
impl<'tcx> HasTargetSpec for TyCtxtAt<'tcx> {
|
||||
fn target_spec(&self) -> &Target {
|
||||
&self.sess.target
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> {
|
||||
impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> {
|
||||
#[inline]
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
**self
|
||||
@ -683,7 +684,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
|
||||
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> {
|
||||
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
|
||||
|
||||
#[inline]
|
||||
|
@ -122,8 +122,6 @@ pub mod inhabitedness;
|
||||
pub mod layout;
|
||||
pub mod normalize_erasing_regions;
|
||||
pub mod print;
|
||||
#[macro_use]
|
||||
pub mod query;
|
||||
pub mod relate;
|
||||
pub mod subst;
|
||||
pub mod trait_def;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
|
||||
use crate::query::IntoQueryParam;
|
||||
use crate::query::Providers;
|
||||
use crate::ty::query::IntoQueryParam;
|
||||
use crate::ty::{
|
||||
self, ConstInt, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable,
|
||||
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||
@ -703,7 +703,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||
ty::Error(_) => p!("[type error]"),
|
||||
ty::Param(ref param_ty) => p!(print(param_ty)),
|
||||
ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
|
||||
ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?,
|
||||
ty::BoundTyKind::Anon => debug_bound_var(&mut self, debruijn, bound_ty.var)?,
|
||||
ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() {
|
||||
true if debruijn == ty::INNERMOST => p!(write("^{}", s)),
|
||||
true => p!(write("^{}_{}", debruijn.index(), s)),
|
||||
@ -741,7 +741,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||
}
|
||||
ty::Placeholder(placeholder) => match placeholder.bound.kind {
|
||||
ty::BoundTyKind::Anon => {
|
||||
self.pretty_print_placeholder_var(placeholder.universe, placeholder.bound.var)?
|
||||
debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound.var)?;
|
||||
}
|
||||
ty::BoundTyKind::Param(_, name) => p!(write("{}", name)),
|
||||
},
|
||||
@ -1164,30 +1164,6 @@ pub trait PrettyPrinter<'tcx>:
|
||||
traits.entry(trait_ref).or_default().extend(proj_ty);
|
||||
}
|
||||
|
||||
fn pretty_print_bound_var(
|
||||
&mut self,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
var: ty::BoundVar,
|
||||
) -> Result<(), Self::Error> {
|
||||
if debruijn == ty::INNERMOST {
|
||||
write!(self, "^{}", var.index())
|
||||
} else {
|
||||
write!(self, "^{}_{}", debruijn.index(), var.index())
|
||||
}
|
||||
}
|
||||
|
||||
fn pretty_print_placeholder_var(
|
||||
&mut self,
|
||||
ui: ty::UniverseIndex,
|
||||
var: ty::BoundVar,
|
||||
) -> Result<(), Self::Error> {
|
||||
if ui == ty::UniverseIndex::ROOT {
|
||||
write!(self, "!{}", var.index())
|
||||
} else {
|
||||
write!(self, "!{}_{}", ui.index(), var.index())
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> {
|
||||
None
|
||||
}
|
||||
@ -1321,7 +1297,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||
define_scoped_cx!(self);
|
||||
|
||||
if self.should_print_verbose() {
|
||||
p!(write("Const({:?}: {:?})", ct.kind(), ct.ty()));
|
||||
p!(write("{:?}", ct));
|
||||
return Ok(self);
|
||||
}
|
||||
|
||||
@ -1380,9 +1356,11 @@ pub trait PrettyPrinter<'tcx>:
|
||||
}
|
||||
|
||||
ty::ConstKind::Bound(debruijn, bound_var) => {
|
||||
self.pretty_print_bound_var(debruijn, bound_var)?
|
||||
debug_bound_var(&mut self, debruijn, bound_var)?
|
||||
}
|
||||
ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
|
||||
ty::ConstKind::Placeholder(placeholder) => {
|
||||
debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound)?;
|
||||
},
|
||||
// FIXME(generic_const_exprs):
|
||||
// write out some legible representation of an abstract const?
|
||||
ty::ConstKind::Expr(_) => p!("[const expr]"),
|
||||
@ -3067,3 +3045,27 @@ pub struct OpaqueFnEntry<'tcx> {
|
||||
fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
|
||||
return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
|
||||
}
|
||||
|
||||
pub fn debug_bound_var<T: std::fmt::Write>(
|
||||
fmt: &mut T,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
var: ty::BoundVar,
|
||||
) -> Result<(), std::fmt::Error> {
|
||||
if debruijn == ty::INNERMOST {
|
||||
write!(fmt, "^{}", var.index())
|
||||
} else {
|
||||
write!(fmt, "^{}_{}", debruijn.index(), var.index())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn debug_placeholder_var<T: std::fmt::Write>(
|
||||
fmt: &mut T,
|
||||
universe: ty::UniverseIndex,
|
||||
bound: ty::BoundVar,
|
||||
) -> Result<(), std::fmt::Error> {
|
||||
if universe == ty::UniverseIndex::ROOT {
|
||||
write!(fmt, "!{}", bound.index())
|
||||
} else {
|
||||
write!(fmt, "!{}_{}", universe.index(), bound.index())
|
||||
}
|
||||
}
|
||||
|
@ -192,6 +192,44 @@ impl<'tcx> fmt::Debug for AliasTy<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
InferConst::Var(var) => write!(f, "{var:?}"),
|
||||
InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// This reflects what `Const` looked liked before `Interned` was
|
||||
// introduced. We print it like this to avoid having to update expected
|
||||
// output in a lot of tests.
|
||||
write!(f, "Const {{ ty: {:?}, kind: {:?} }}", self.ty(), self.kind())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::ConstKind<'tcx> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use ty::ConstKind::*;
|
||||
match self {
|
||||
Param(param) => write!(f, "{param:?}"),
|
||||
Infer(var) => write!(f, "{var:?}"),
|
||||
Bound(debruijn, var) => ty::print::debug_bound_var(f, *debruijn, *var),
|
||||
Placeholder(placeholder) => {
|
||||
ty::print::debug_placeholder_var(f, placeholder.universe, placeholder.bound)
|
||||
}
|
||||
Unevaluated(uv) => {
|
||||
f.debug_tuple("Unevaluated").field(&uv.substs).field(&uv.def).finish()
|
||||
}
|
||||
Value(valtree) => write!(f, "{valtree:?}"),
|
||||
Error(_) => write!(f, "[const error]"),
|
||||
Expr(expr) => write!(f, "{expr:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Atomic structs
|
||||
//
|
||||
|
@ -1708,7 +1708,9 @@ impl<'tcx> Region<'tcx> {
|
||||
ty::ReErased => {
|
||||
flags = flags | TypeFlags::HAS_RE_ERASED;
|
||||
}
|
||||
ty::ReError(_) => {}
|
||||
ty::ReError(_) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
}
|
||||
}
|
||||
|
||||
debug!("type_flags({:?}) = {:?}", self, flags);
|
||||
|
@ -668,10 +668,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> impl Iterator<Item = ty::EarlyBinder<Ty<'tcx>>> {
|
||||
let generator_layout = &self.mir_generator_witnesses(def_id);
|
||||
let generator_layout = self.mir_generator_witnesses(def_id);
|
||||
generator_layout
|
||||
.field_tys
|
||||
.iter()
|
||||
.as_ref()
|
||||
.map_or_else(|| [].iter(), |l| l.field_tys.iter())
|
||||
.filter(|decl| !decl.ignore_for_traits)
|
||||
.map(|decl| ty::EarlyBinder(decl.ty))
|
||||
}
|
||||
|
@ -481,9 +481,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}))))
|
||||
}
|
||||
|
||||
ExprKind::OffsetOf { container, fields } => {
|
||||
block.and(Rvalue::NullaryOp(NullOp::OffsetOf(fields), container))
|
||||
}
|
||||
ExprKind::OffsetOf { container, fields } => block.and(Rvalue::NullaryOp(
|
||||
NullOp::OffsetOf(fields),
|
||||
this.tcx.erase_regions(container),
|
||||
)),
|
||||
|
||||
ExprKind::Literal { .. }
|
||||
| ExprKind::NamedConst { .. }
|
||||
|
@ -380,18 +380,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
/// Compare two `&T` values using `<T as std::compare::PartialEq>::eq`
|
||||
/// Compare two values using `<T as std::compare::PartialEq>::eq`.
|
||||
/// If the values are already references, just call it directly, otherwise
|
||||
/// take a reference to the values first and then call it.
|
||||
fn non_scalar_compare(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
|
||||
source_info: SourceInfo,
|
||||
value: ConstantKind<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
mut val: Place<'tcx>,
|
||||
mut ty: Ty<'tcx>,
|
||||
) {
|
||||
let mut expect = self.literal_operand(source_info.span, value);
|
||||
let mut val = Operand::Copy(place);
|
||||
|
||||
// If we're using `b"..."` as a pattern, we need to insert an
|
||||
// unsizing coercion, as the byte string has the type `&[u8; N]`.
|
||||
@ -421,9 +422,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block,
|
||||
source_info,
|
||||
temp,
|
||||
Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), val, ty),
|
||||
Rvalue::Cast(
|
||||
CastKind::Pointer(PointerCast::Unsize),
|
||||
Operand::Copy(val),
|
||||
ty,
|
||||
),
|
||||
);
|
||||
val = Operand::Move(temp);
|
||||
val = temp;
|
||||
}
|
||||
if opt_ref_test_ty.is_some() {
|
||||
let slice = self.temp(ty, source_info.span);
|
||||
@ -438,12 +443,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let ty::Ref(_, deref_ty, _) = *ty.kind() else {
|
||||
bug!("non_scalar_compare called on non-reference type: {}", ty);
|
||||
};
|
||||
match *ty.kind() {
|
||||
ty::Ref(_, deref_ty, _) => ty = deref_ty,
|
||||
_ => {
|
||||
// non_scalar_compare called on non-reference type
|
||||
let temp = self.temp(ty, source_info.span);
|
||||
self.cfg.push_assign(block, source_info, temp, Rvalue::Use(expect));
|
||||
let ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, ty);
|
||||
let ref_temp = self.temp(ref_ty, source_info.span);
|
||||
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
ref_temp,
|
||||
Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, temp),
|
||||
);
|
||||
expect = Operand::Move(ref_temp);
|
||||
|
||||
let ref_temp = self.temp(ref_ty, source_info.span);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
ref_temp,
|
||||
Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, val),
|
||||
);
|
||||
val = ref_temp;
|
||||
}
|
||||
}
|
||||
|
||||
let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
|
||||
let method = trait_method(self.tcx, eq_def_id, sym::eq, [deref_ty, deref_ty]);
|
||||
let method = trait_method(self.tcx, eq_def_id, sym::eq, [ty, ty]);
|
||||
|
||||
let bool_ty = self.tcx.types.bool;
|
||||
let eq_result = self.temp(bool_ty, source_info.span);
|
||||
@ -463,7 +492,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
literal: method,
|
||||
})),
|
||||
args: vec![val, expect],
|
||||
args: vec![Operand::Copy(val), expect],
|
||||
destination: eq_result,
|
||||
target: Some(eq_block),
|
||||
unwind: UnwindAction::Continue,
|
||||
|
@ -62,21 +62,13 @@ struct ConstToPat<'tcx> {
|
||||
treat_byte_string_as_slice: bool,
|
||||
}
|
||||
|
||||
mod fallback_to_const_ref {
|
||||
#[derive(Debug)]
|
||||
/// This error type signals that we encountered a non-struct-eq situation behind a reference.
|
||||
/// We bubble this up in order to get back to the reference destructuring and make that emit
|
||||
/// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq`
|
||||
/// on such patterns (since that function takes a reference) and not have to jump through any
|
||||
/// hoops to get a reference to the value.
|
||||
pub(super) struct FallbackToConstRef(());
|
||||
|
||||
pub(super) fn fallback_to_const_ref(c2p: &super::ConstToPat<'_>) -> FallbackToConstRef {
|
||||
assert!(c2p.behind_reference.get());
|
||||
FallbackToConstRef(())
|
||||
}
|
||||
}
|
||||
use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef};
|
||||
/// This error type signals that we encountered a non-struct-eq situation.
|
||||
/// We bubble this up in order to get back to the reference destructuring and make that emit
|
||||
/// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq`
|
||||
/// on such patterns (since that function takes a reference) and not have to jump through any
|
||||
/// hoops to get a reference to the value.
|
||||
#[derive(Debug)]
|
||||
struct FallbackToConstRef;
|
||||
|
||||
impl<'tcx> ConstToPat<'tcx> {
|
||||
fn new(
|
||||
@ -236,13 +228,13 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
|
||||
let kind = match cv.ty().kind() {
|
||||
ty::Float(_) => {
|
||||
tcx.emit_spanned_lint(
|
||||
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
||||
id,
|
||||
span,
|
||||
FloatPattern,
|
||||
);
|
||||
PatKind::Constant { value: cv }
|
||||
tcx.emit_spanned_lint(
|
||||
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
||||
id,
|
||||
span,
|
||||
FloatPattern,
|
||||
);
|
||||
return Err(FallbackToConstRef);
|
||||
}
|
||||
ty::Adt(adt_def, _) if adt_def.is_union() => {
|
||||
// Matching on union fields is unsafe, we can't hide it in constants
|
||||
@ -289,7 +281,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
// Since we are behind a reference, we can just bubble the error up so we get a
|
||||
// constant at reference type, making it easy to let the fallback call
|
||||
// `PartialEq::eq` on it.
|
||||
return Err(fallback_to_const_ref(self));
|
||||
return Err(FallbackToConstRef);
|
||||
}
|
||||
ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty()) => {
|
||||
debug!(
|
||||
@ -393,11 +385,11 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
self.behind_reference.set(old);
|
||||
val
|
||||
}
|
||||
// Backwards compatibility hack: support references to non-structural types.
|
||||
// We'll lower
|
||||
// this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a
|
||||
// reference. This makes the rest of the matching logic simpler as it doesn't have
|
||||
// to figure out how to get a reference again.
|
||||
// Backwards compatibility hack: support references to non-structural types,
|
||||
// but hard error if we aren't behind a double reference. We could just use
|
||||
// the fallback code path below, but that would allow *more* of this fishy
|
||||
// code to compile, as then it only goes through the future incompat lint
|
||||
// instead of a hard error.
|
||||
ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => {
|
||||
if self.behind_reference.get() {
|
||||
if !self.saw_const_match_error.get()
|
||||
@ -411,7 +403,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
IndirectStructuralMatch { non_sm_ty: *pointee_ty },
|
||||
);
|
||||
}
|
||||
PatKind::Constant { value: cv }
|
||||
return Err(FallbackToConstRef);
|
||||
} else {
|
||||
if !self.saw_const_match_error.get() {
|
||||
self.saw_const_match_error.set(true);
|
||||
@ -435,16 +427,9 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
PatKind::Wild
|
||||
} else {
|
||||
let old = self.behind_reference.replace(true);
|
||||
// In case there are structural-match violations somewhere in this subpattern,
|
||||
// we fall back to a const pattern. If we do not do this, we may end up with
|
||||
// a !structural-match constant that is not of reference type, which makes it
|
||||
// very hard to invoke `PartialEq::eq` on it as a fallback.
|
||||
let val = match self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false) {
|
||||
Ok(subpattern) => PatKind::Deref { subpattern },
|
||||
Err(_) => PatKind::Constant { value: cv },
|
||||
};
|
||||
let subpattern = self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false)?;
|
||||
self.behind_reference.set(old);
|
||||
val
|
||||
PatKind::Deref { subpattern }
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -452,7 +437,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
PatKind::Constant { value: cv }
|
||||
}
|
||||
ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => {
|
||||
PatKind::Constant { value: cv }
|
||||
return Err(FallbackToConstRef);
|
||||
}
|
||||
// FIXME: these can have very surprising behaviour where optimization levels or other
|
||||
// compilation choices change the runtime behaviour of the match.
|
||||
@ -469,7 +454,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
PointerPattern
|
||||
);
|
||||
}
|
||||
PatKind::Constant { value: cv }
|
||||
return Err(FallbackToConstRef);
|
||||
}
|
||||
_ => {
|
||||
self.saw_const_match_error.set(true);
|
||||
|
@ -844,8 +844,8 @@ impl<'tcx> Constructor<'tcx> {
|
||||
}
|
||||
|
||||
/// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is
|
||||
/// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is
|
||||
/// assumed to have been split from a wildcard.
|
||||
/// assumed to be built from `matrix.head_ctors()` with wildcards and opaques filtered out,
|
||||
/// and `self` is assumed to have been split from a wildcard.
|
||||
fn is_covered_by_any<'p>(
|
||||
&self,
|
||||
pcx: &PatCtxt<'_, 'p, 'tcx>,
|
||||
@ -894,7 +894,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||
/// in `to_ctors`: in some cases we only return `Missing`.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct SplitWildcard<'tcx> {
|
||||
/// Constructors seen in the matrix.
|
||||
/// Constructors (other than wildcards and opaques) seen in the matrix.
|
||||
matrix_ctors: Vec<Constructor<'tcx>>,
|
||||
/// All the constructors for this type
|
||||
all_ctors: SmallVec<[Constructor<'tcx>; 1]>,
|
||||
@ -1037,7 +1037,7 @@ impl<'tcx> SplitWildcard<'tcx> {
|
||||
// Since `all_ctors` never contains wildcards, this won't recurse further.
|
||||
self.all_ctors =
|
||||
self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect();
|
||||
self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect();
|
||||
self.matrix_ctors = ctors.filter(|c| !matches!(c, Wildcard | Opaque)).cloned().collect();
|
||||
}
|
||||
|
||||
/// Whether there are any value constructors for this type that are not present in the matrix.
|
||||
|
@ -288,6 +288,22 @@
|
||||
//!
|
||||
//! The details are not necessary to understand this file, so we explain them in
|
||||
//! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function.
|
||||
//!
|
||||
//! # Constants in patterns
|
||||
//!
|
||||
//! There are two kinds of constants in patterns:
|
||||
//!
|
||||
//! * literals (`1`, `true`, `"foo"`)
|
||||
//! * named or inline consts (`FOO`, `const { 5 + 6 }`)
|
||||
//!
|
||||
//! The latter are converted into other patterns with literals at the leaves. For example
|
||||
//! `const_to_pat(const { [1, 2, 3] })` becomes an `Array(vec![Const(1), Const(2), Const(3)])`
|
||||
//! pattern. This gets problematic when comparing the constant via `==` would behave differently
|
||||
//! from matching on the constant converted to a pattern. Situations like that can occur, when
|
||||
//! the user implements `PartialEq` manually, and thus could make `==` behave arbitrarily different.
|
||||
//! In order to honor the `==` implementation, constants of types that implement `PartialEq` manually
|
||||
//! stay as a full constant and become an `Opaque` pattern. These `Opaque` patterns do not participate
|
||||
//! in exhaustiveness, specialization or overlap checking.
|
||||
|
||||
use self::ArmType::*;
|
||||
use self::Usefulness::*;
|
||||
|
@ -276,6 +276,7 @@ where
|
||||
assert_eq!(self.elaborator.param_env().reveal(), Reveal::All);
|
||||
let field_ty =
|
||||
tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs));
|
||||
|
||||
(tcx.mk_place_field(base_place, field, field_ty), subpath)
|
||||
})
|
||||
.collect()
|
||||
|
@ -162,20 +162,22 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) {
|
||||
match stmt.kind {
|
||||
// When removing storage statements, we need to remove both (#107511).
|
||||
StatementKind::StorageLive(l) | StatementKind::StorageDead(l)
|
||||
if self.storage_to_remove.contains(l) =>
|
||||
{
|
||||
stmt.make_nop()
|
||||
}
|
||||
StatementKind::Assign(box (ref place, ref mut rvalue))
|
||||
if place.as_local().is_some() =>
|
||||
{
|
||||
// Do not replace assignments.
|
||||
self.visit_rvalue(rvalue, loc)
|
||||
}
|
||||
_ => self.super_statement(stmt, loc),
|
||||
// When removing storage statements, we need to remove both (#107511).
|
||||
if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = stmt.kind
|
||||
&& self.storage_to_remove.contains(l)
|
||||
{
|
||||
stmt.make_nop();
|
||||
return
|
||||
}
|
||||
|
||||
self.super_statement(stmt, loc);
|
||||
|
||||
// Do not leave tautological assignments around.
|
||||
if let StatementKind::Assign(box (lhs, ref rhs)) = stmt.kind
|
||||
&& let Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)) | Rvalue::CopyForDeref(rhs) = *rhs
|
||||
&& lhs == rhs
|
||||
{
|
||||
stmt.make_nop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1397,7 +1397,7 @@ fn create_cases<'tcx>(
|
||||
pub(crate) fn mir_generator_witnesses<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> GeneratorLayout<'tcx> {
|
||||
) -> Option<GeneratorLayout<'tcx>> {
|
||||
assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
|
||||
|
||||
let (body, _) = tcx.mir_promoted(def_id);
|
||||
@ -1410,6 +1410,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>(
|
||||
// Get the interior types and substs which typeck computed
|
||||
let movable = match *gen_ty.kind() {
|
||||
ty::Generator(_, _, movability) => movability == hir::Movability::Movable,
|
||||
ty::Error(_) => return None,
|
||||
_ => span_bug!(body.span, "unexpected generator type {}", gen_ty),
|
||||
};
|
||||
|
||||
@ -1425,7 +1426,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>(
|
||||
|
||||
check_suspend_tys(tcx, &generator_layout, &body);
|
||||
|
||||
generator_layout
|
||||
Some(generator_layout)
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for StateTransform {
|
||||
|
@ -7,6 +7,7 @@ use rustc_index::Idx;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::mir::visit::*;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span};
|
||||
@ -168,7 +169,7 @@ impl<'tcx> Inliner<'tcx> {
|
||||
let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id());
|
||||
self.check_codegen_attributes(callsite, callee_attrs)?;
|
||||
self.check_mir_is_available(caller_body, &callsite.callee)?;
|
||||
let callee_body = self.tcx.instance_mir(callsite.callee.def);
|
||||
let callee_body = try_instance_mir(self.tcx, callsite.callee.def)?;
|
||||
self.check_mir_body(callsite, callee_body, callee_attrs)?;
|
||||
|
||||
if !self.tcx.consider_optimizing(|| {
|
||||
@ -1128,3 +1129,27 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
fn try_instance_mir<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: InstanceDef<'tcx>,
|
||||
) -> Result<&'tcx Body<'tcx>, &'static str> {
|
||||
match instance {
|
||||
ty::InstanceDef::DropGlue(_, Some(ty)) => match ty.kind() {
|
||||
ty::Adt(def, substs) => {
|
||||
let fields = def.all_fields();
|
||||
for field in fields {
|
||||
let field_ty = field.ty(tcx, substs);
|
||||
if field_ty.has_param() && field_ty.has_projections() {
|
||||
return Err("cannot build drop shim for polymorphic type");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(tcx.instance_mir(instance))
|
||||
}
|
||||
_ => Ok(tcx.instance_mir(instance)),
|
||||
},
|
||||
_ => Ok(tcx.instance_mir(instance)),
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ use crate::MirPass;
|
||||
use rustc_hir::Mutability;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::layout::ValidityRequirement;
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_target::abi::FieldIdx;
|
||||
@ -163,18 +162,6 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
|
||||
return;
|
||||
}
|
||||
|
||||
// Transmuting a fieldless enum to its repr is a discriminant read
|
||||
if let ty::Adt(adt_def, ..) = operand_ty.kind()
|
||||
&& adt_def.is_enum()
|
||||
&& adt_def.is_payloadfree()
|
||||
&& let Some(place) = operand.place()
|
||||
&& let Some(repr_int) = adt_def.repr().int
|
||||
&& repr_int.to_ty(self.tcx) == *cast_ty
|
||||
{
|
||||
*rvalue = Rvalue::Discriminant(place);
|
||||
return;
|
||||
}
|
||||
|
||||
// Transmuting a transparent struct/union to a field's type is a projection
|
||||
if let ty::Adt(adt_def, substs) = operand_ty.kind()
|
||||
&& adt_def.repr().transparent()
|
||||
|
@ -101,14 +101,15 @@ impl SsaLocals {
|
||||
.retain(|&local| matches!(visitor.assignments[local], Set1::One(_)));
|
||||
debug!(?visitor.assignment_order);
|
||||
|
||||
let copy_classes = compute_copy_classes(&mut visitor, body);
|
||||
|
||||
SsaLocals {
|
||||
let mut ssa = SsaLocals {
|
||||
assignments: visitor.assignments,
|
||||
assignment_order: visitor.assignment_order,
|
||||
direct_uses: visitor.direct_uses,
|
||||
copy_classes,
|
||||
}
|
||||
// This is filled by `compute_copy_classes`.
|
||||
copy_classes: IndexVec::default(),
|
||||
};
|
||||
compute_copy_classes(&mut ssa, body);
|
||||
ssa
|
||||
}
|
||||
|
||||
pub fn num_locals(&self) -> usize {
|
||||
@ -261,49 +262,54 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor {
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(ssa, body))]
|
||||
fn compute_copy_classes(ssa: &mut SsaVisitor, body: &Body<'_>) -> IndexVec<Local, Local> {
|
||||
fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) {
|
||||
let mut direct_uses = std::mem::take(&mut ssa.direct_uses);
|
||||
let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len());
|
||||
|
||||
for &local in &ssa.assignment_order {
|
||||
debug!(?local);
|
||||
|
||||
if local == RETURN_PLACE {
|
||||
// `_0` is special, we cannot rename it.
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is not SSA: mark that we don't know the value.
|
||||
debug!(assignments = ?ssa.assignments[local]);
|
||||
let Set1::One(LocationExtended::Plain(loc)) = ssa.assignments[local] else { continue };
|
||||
|
||||
// `loc` must point to a direct assignment to `local`.
|
||||
let Either::Left(stmt) = body.stmt_at(loc) else { bug!() };
|
||||
let Some((_target, rvalue)) = stmt.kind.as_assign() else { bug!() };
|
||||
assert_eq!(_target.as_local(), Some(local));
|
||||
|
||||
for (local, rvalue, _) in ssa.assignments(body) {
|
||||
let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place))
|
||||
= rvalue
|
||||
else { continue };
|
||||
|
||||
let Some(rhs) = place.as_local() else { continue };
|
||||
let Set1::One(_) = ssa.assignments[rhs] else { continue };
|
||||
if !ssa.is_ssa(rhs) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We visit in `assignment_order`, ie. reverse post-order, so `rhs` has been
|
||||
// visited before `local`, and we just have to copy the representing local.
|
||||
copies[local] = copies[rhs];
|
||||
ssa.direct_uses[rhs] -= 1;
|
||||
let head = copies[rhs];
|
||||
|
||||
if local == RETURN_PLACE {
|
||||
// `_0` is special, we cannot rename it. Instead, rename the class of `rhs` to
|
||||
// `RETURN_PLACE`. This is only possible if the class head is a temporary, not an
|
||||
// argument.
|
||||
if body.local_kind(head) != LocalKind::Temp {
|
||||
continue;
|
||||
}
|
||||
for h in copies.iter_mut() {
|
||||
if *h == head {
|
||||
*h = RETURN_PLACE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
copies[local] = head;
|
||||
}
|
||||
direct_uses[rhs] -= 1;
|
||||
}
|
||||
|
||||
debug!(?copies);
|
||||
debug!(?ssa.direct_uses);
|
||||
debug!(?direct_uses);
|
||||
|
||||
// Invariant: `copies` must point to the head of an equivalence class.
|
||||
#[cfg(debug_assertions)]
|
||||
for &head in copies.iter() {
|
||||
assert_eq!(copies[head], head);
|
||||
}
|
||||
debug_assert_eq!(copies[RETURN_PLACE], RETURN_PLACE);
|
||||
|
||||
copies
|
||||
ssa.direct_uses = direct_uses;
|
||||
ssa.copy_classes = copies;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -185,9 +185,9 @@ use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar};
|
||||
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
|
||||
use rustc_middle::mir::visit::Visitor as MirVisitor;
|
||||
use rustc_middle::mir::{self, Local, Location};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::query::TyCtxtAt;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
|
||||
use rustc_middle::ty::{
|
||||
self, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
|
||||
|
@ -12,10 +12,9 @@ extern crate rustc_middle;
|
||||
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
|
||||
use rustc_fluent_macro::fluent_messages;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::query::{Providers, TyCtxtAt};
|
||||
use rustc_middle::traits;
|
||||
use rustc_middle::ty::adjustment::CustomCoerceUnsized;
|
||||
use rustc_middle::ty::query::TyCtxtAt;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
||||
mod collector;
|
||||
|
@ -453,6 +453,8 @@ impl<'a> Parser<'a> {
|
||||
// `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
|
||||
// `<` (LIFETIME|IDENT) `=` - generic parameter with a default
|
||||
// `<` const - generic const parameter
|
||||
// `<` IDENT `?` - RECOVERY for `impl<T ?Bound` missing a `:`, meant to
|
||||
// avoid the `T?` to `Option<T>` recovery for types.
|
||||
// The only truly ambiguous case is
|
||||
// `<` IDENT `>` `::` IDENT ...
|
||||
// we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
|
||||
@ -463,6 +465,9 @@ impl<'a> Parser<'a> {
|
||||
|| self.look_ahead(start + 1, |t| t.is_lifetime() || t.is_ident())
|
||||
&& self.look_ahead(start + 2, |t| {
|
||||
matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq)
|
||||
// Recovery-only branch -- this could be removed,
|
||||
// since it only affects diagnostics currently.
|
||||
|| matches!(t.kind, token::Question)
|
||||
})
|
||||
|| self.is_keyword_ahead(start + 1, &[kw::Const]))
|
||||
}
|
||||
|
@ -24,17 +24,18 @@ use rustc_middle::dep_graph::DepNodeIndex;
|
||||
use rustc_middle::dep_graph::{self, DepKind, DepKindStruct};
|
||||
use rustc_middle::query::erase::{erase, restore, Erase};
|
||||
use rustc_middle::query::on_disk_cache::OnDiskCache;
|
||||
use rustc_middle::query::plumbing::{DynamicQuery, QuerySystem, QuerySystemFns};
|
||||
use rustc_middle::query::AsLocalKey;
|
||||
use rustc_middle::query::{
|
||||
query_keys, query_provided, query_provided_to_value, query_storage, query_values,
|
||||
DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates,
|
||||
};
|
||||
use rustc_middle::ty::query::{DynamicQuery, QuerySystem, QuerySystemFns};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_query_system::dep_graph::SerializedDepNodeIndex;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_query_system::query::{
|
||||
get_query, HashResult, QueryCache, QueryConfig, QueryInfo, QueryMap, QueryMode, QueryState,
|
||||
get_query_incr, get_query_non_incr, HashResult, QueryCache, QueryConfig, QueryInfo, QueryMap,
|
||||
QueryMode, QueryState,
|
||||
};
|
||||
use rustc_query_system::HandleCycleError;
|
||||
use rustc_query_system::Value;
|
||||
@ -203,6 +204,7 @@ pub fn query_system<'tcx>(
|
||||
local_providers: Providers,
|
||||
extern_providers: ExternProviders,
|
||||
on_disk_cache: Option<OnDiskCache<'tcx>>,
|
||||
incremental: bool,
|
||||
) -> QuerySystem<'tcx> {
|
||||
QuerySystem {
|
||||
states: Default::default(),
|
||||
@ -211,7 +213,7 @@ pub fn query_system<'tcx>(
|
||||
dynamic_queries: dynamic_queries(),
|
||||
on_disk_cache,
|
||||
fns: QuerySystemFns {
|
||||
engine: engine(),
|
||||
engine: engine(incremental),
|
||||
local_providers,
|
||||
extern_providers,
|
||||
query_structs: make_dep_kind_array!(query_structs).to_vec(),
|
||||
|
@ -494,7 +494,7 @@ macro_rules! define_queries {
|
||||
(
|
||||
$($(#[$attr:meta])*
|
||||
[$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
|
||||
mod get_query {
|
||||
mod get_query_incr {
|
||||
use super::*;
|
||||
|
||||
$(
|
||||
@ -506,7 +506,7 @@ macro_rules! define_queries {
|
||||
key: query_keys::$name<'tcx>,
|
||||
mode: QueryMode,
|
||||
) -> Option<Erase<query_values::$name<'tcx>>> {
|
||||
get_query(
|
||||
get_query_incr(
|
||||
queries::$name::config(tcx),
|
||||
QueryCtxt::new(tcx),
|
||||
span,
|
||||
@ -517,9 +517,37 @@ macro_rules! define_queries {
|
||||
)*
|
||||
}
|
||||
|
||||
pub(crate) fn engine() -> QueryEngine {
|
||||
QueryEngine {
|
||||
$($name: get_query::$name,)*
|
||||
mod get_query_non_incr {
|
||||
use super::*;
|
||||
|
||||
$(
|
||||
#[inline(always)]
|
||||
#[tracing::instrument(level = "trace", skip(tcx))]
|
||||
pub(super) fn $name<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
key: query_keys::$name<'tcx>,
|
||||
__mode: QueryMode,
|
||||
) -> Option<Erase<query_values::$name<'tcx>>> {
|
||||
Some(get_query_non_incr(
|
||||
queries::$name::config(tcx),
|
||||
QueryCtxt::new(tcx),
|
||||
span,
|
||||
key,
|
||||
))
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
pub(crate) fn engine(incremental: bool) -> QueryEngine {
|
||||
if incremental {
|
||||
QueryEngine {
|
||||
$($name: get_query_incr::$name,)*
|
||||
}
|
||||
} else {
|
||||
QueryEngine {
|
||||
$($name: get_query_non_incr::$name,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -688,8 +716,7 @@ macro_rules! define_queries {
|
||||
|
||||
mod query_structs {
|
||||
use super::*;
|
||||
use rustc_middle::ty::query::QueryStruct;
|
||||
use rustc_middle::ty::query::QueryKeyStringCache;
|
||||
use rustc_middle::query::plumbing::{QueryKeyStringCache, QueryStruct};
|
||||
use rustc_middle::dep_graph::DepKind;
|
||||
use crate::QueryConfigRestored;
|
||||
|
||||
|
@ -2,7 +2,7 @@ use measureme::{StringComponent, StringId};
|
||||
use rustc_data_structures::profiling::SelfProfiler;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
use rustc_middle::ty::query::QueryKeyStringCache;
|
||||
use rustc_middle::query::plumbing::QueryKeyStringCache;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_query_system::query::QueryCache;
|
||||
use std::fmt::Debug;
|
||||
|
@ -312,7 +312,7 @@ where
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn try_execute_query<Q, Qcx>(
|
||||
fn try_execute_query<Q, Qcx, const INCR: bool>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
span: Span,
|
||||
@ -355,7 +355,7 @@ where
|
||||
// Drop the lock before we start executing the query
|
||||
drop(state_lock);
|
||||
|
||||
execute_job(query, qcx, state, key, id, dep_node)
|
||||
execute_job::<_, _, INCR>(query, qcx, state, key, id, dep_node)
|
||||
}
|
||||
Entry::Occupied(mut entry) => {
|
||||
match entry.get_mut() {
|
||||
@ -383,7 +383,7 @@ where
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn execute_job<Q, Qcx>(
|
||||
fn execute_job<Q, Qcx, const INCR: bool>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
state: &QueryState<Q::Key, Qcx::DepKind>,
|
||||
@ -398,9 +398,19 @@ where
|
||||
// Use `JobOwner` so the query will be poisoned if executing it panics.
|
||||
let job_owner = JobOwner { state, key };
|
||||
|
||||
let (result, dep_node_index) = match qcx.dep_context().dep_graph().data() {
|
||||
None => execute_job_non_incr(query, qcx, key, id),
|
||||
Some(data) => execute_job_incr(query, qcx, data, key, dep_node, id),
|
||||
debug_assert_eq!(qcx.dep_context().dep_graph().is_fully_enabled(), INCR);
|
||||
|
||||
let (result, dep_node_index) = if INCR {
|
||||
execute_job_incr(
|
||||
query,
|
||||
qcx,
|
||||
qcx.dep_context().dep_graph().data().unwrap(),
|
||||
key,
|
||||
dep_node,
|
||||
id,
|
||||
)
|
||||
} else {
|
||||
execute_job_non_incr(query, qcx, key, id)
|
||||
};
|
||||
|
||||
let cache = query.query_cache(qcx);
|
||||
@ -784,7 +794,18 @@ pub enum QueryMode {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_query<Q, Qcx>(
|
||||
pub fn get_query_non_incr<Q, Qcx>(query: Q, qcx: Qcx, span: Span, key: Q::Key) -> Q::Value
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
{
|
||||
debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled());
|
||||
|
||||
ensure_sufficient_stack(|| try_execute_query::<Q, Qcx, false>(query, qcx, span, key, None).0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_query_incr<Q, Qcx>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
span: Span,
|
||||
@ -795,6 +816,8 @@ where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
{
|
||||
debug_assert!(qcx.dep_context().dep_graph().is_fully_enabled());
|
||||
|
||||
let dep_node = if let QueryMode::Ensure { check_cache } = mode {
|
||||
let (must_run, dep_node) = ensure_must_run(query, qcx, &key, check_cache);
|
||||
if !must_run {
|
||||
@ -805,8 +828,9 @@ where
|
||||
None
|
||||
};
|
||||
|
||||
let (result, dep_node_index) =
|
||||
ensure_sufficient_stack(|| try_execute_query(query, qcx, span, key, dep_node));
|
||||
let (result, dep_node_index) = ensure_sufficient_stack(|| {
|
||||
try_execute_query::<_, _, true>(query, qcx, span, key, dep_node)
|
||||
});
|
||||
if let Some(dep_node_index) = dep_node_index {
|
||||
qcx.dep_context().dep_graph().read_index(dep_node_index)
|
||||
}
|
||||
@ -831,5 +855,7 @@ pub fn force_query<Q, Qcx>(
|
||||
|
||||
debug_assert!(!query.anon());
|
||||
|
||||
ensure_sufficient_stack(|| try_execute_query(query, qcx, DUMMY_SP, key, Some(dep_node)));
|
||||
ensure_sufficient_stack(|| {
|
||||
try_execute_query::<_, _, true>(query, qcx, DUMMY_SP, key, Some(dep_node))
|
||||
});
|
||||
}
|
||||
|
@ -550,7 +550,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
|
||||
let sm = self.tcx.sess.source_map();
|
||||
let def_id = match outer_res {
|
||||
Res::SelfTyParam { .. } | Res::SelfCtor(_) => {
|
||||
Res::SelfTyParam { .. } => {
|
||||
err.span_label(span, "can't use `Self` here");
|
||||
return err;
|
||||
}
|
||||
|
@ -1174,10 +1174,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
return Res::Err;
|
||||
}
|
||||
}
|
||||
Res::Def(DefKind::TyParam, _)
|
||||
| Res::SelfTyParam { .. }
|
||||
| Res::SelfTyAlias { .. }
|
||||
| Res::SelfCtor(_) => {
|
||||
Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {
|
||||
for rib in ribs {
|
||||
let has_generic_params: HasGenericParams = match rib.kind {
|
||||
RibKind::Normal
|
||||
|
@ -3543,10 +3543,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
//
|
||||
// Similar thing, for types, happens in `report_errors` above.
|
||||
let report_errors_for_call = |this: &mut Self, parent_err: Spanned<ResolutionError<'a>>| {
|
||||
if !source.is_call() {
|
||||
return Some(parent_err);
|
||||
}
|
||||
|
||||
// Before we start looking for candidates, we have to get our hands
|
||||
// on the type user is trying to perform invocation on; basically:
|
||||
// we're transforming `HashMap::new` into just `HashMap`.
|
||||
|
@ -6,7 +6,8 @@ use crate::search_paths::PathKind;
|
||||
use crate::utils::NativeLibKind;
|
||||
use crate::Session;
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::sync::{self, AppendOnlyIndexVec, MetadataRef, RwLock};
|
||||
use rustc_data_structures::owned_slice::OwnedSlice;
|
||||
use rustc_data_structures::sync::{self, AppendOnlyIndexVec, RwLock};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE};
|
||||
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};
|
||||
use rustc_span::hygiene::{ExpnHash, ExpnId};
|
||||
@ -203,8 +204,8 @@ pub enum ExternCrateSource {
|
||||
/// metadata in library -- this trait just serves to decouple rustc_metadata from
|
||||
/// the archive reader, which depends on LLVM.
|
||||
pub trait MetadataLoader: std::fmt::Debug {
|
||||
fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>;
|
||||
fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>;
|
||||
fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
|
||||
fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
|
||||
}
|
||||
|
||||
pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync;
|
||||
|
@ -164,6 +164,7 @@ symbols! {
|
||||
Capture,
|
||||
Center,
|
||||
Clone,
|
||||
ConstParamTy,
|
||||
Context,
|
||||
Continue,
|
||||
Copy,
|
||||
@ -1583,6 +1584,7 @@ symbols! {
|
||||
unrestricted_attribute_tokens,
|
||||
unsafe_block_in_unsafe_fn,
|
||||
unsafe_cell,
|
||||
unsafe_cell_from_mut,
|
||||
unsafe_no_drop_flag,
|
||||
unsafe_pin_internals,
|
||||
unsize,
|
||||
|
@ -124,10 +124,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||
};
|
||||
|
||||
if !assoc_def.item.defaultness(tcx).has_value() {
|
||||
tcx.sess.delay_span_bug(
|
||||
let guar = tcx.sess.delay_span_bug(
|
||||
tcx.def_span(assoc_def.item.def_id),
|
||||
"missing value for assoc item in impl",
|
||||
);
|
||||
let error_term = match assoc_def.item.kind {
|
||||
ty::AssocKind::Const => tcx
|
||||
.const_error(
|
||||
tcx.type_of(goal.predicate.def_id())
|
||||
.subst(tcx, goal.predicate.projection_ty.substs),
|
||||
guar,
|
||||
)
|
||||
.into(),
|
||||
ty::AssocKind::Type => tcx.ty_error(guar).into(),
|
||||
ty::AssocKind::Fn => unreachable!(),
|
||||
};
|
||||
ecx.eq(goal.param_env, goal.predicate.term, error_term)
|
||||
.expect("expected goal term to be fully unconstrained");
|
||||
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
|
||||
}
|
||||
|
||||
// Getting the right substitutions here is complex, e.g. given:
|
||||
|
@ -801,7 +801,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||
span: tcx.def_span(unevaluated.def),
|
||||
unevaluated: unevaluated,
|
||||
});
|
||||
Err(ErrorHandled::Reported(reported))
|
||||
Err(ErrorHandled::Reported(reported.into()))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ pub fn is_const_evaluatable<'tcx>(
|
||||
"Missing value for constant, but no error reported?",
|
||||
)))
|
||||
}
|
||||
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
|
||||
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())),
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
@ -147,7 +147,7 @@ pub fn is_const_evaluatable<'tcx>(
|
||||
|
||||
Err(err)
|
||||
}
|
||||
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
|
||||
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())),
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
@ -2447,10 +2447,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
&& generator_did.is_local()
|
||||
// Try to avoid cycles.
|
||||
&& !generator_within_in_progress_typeck
|
||||
&& let Some(generator_info) = self.tcx.mir_generator_witnesses(generator_did)
|
||||
{
|
||||
let generator_info = &self.tcx.mir_generator_witnesses(generator_did);
|
||||
debug!(?generator_info);
|
||||
|
||||
'find_source: for (variant, source_info) in
|
||||
generator_info.variant_fields.iter().zip(&generator_info.variant_source_info)
|
||||
{
|
||||
|
@ -615,7 +615,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
||||
(Err(ErrorHandled::Reported(reported)), _)
|
||||
| (_, Err(ErrorHandled::Reported(reported))) => ProcessResult::Error(
|
||||
CodeSelectionError(SelectionError::NotConstEvaluatable(
|
||||
NotConstEvaluatable::Error(reported),
|
||||
NotConstEvaluatable::Error(reported.into()),
|
||||
)),
|
||||
),
|
||||
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
|
||||
|
@ -3021,7 +3021,7 @@ impl<'a, K, V, A> CursorMut<'a, K, V, A> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the of the element that the cursor is
|
||||
/// Returns a mutable reference to the key of the element that the cursor is
|
||||
/// currently pointing to.
|
||||
///
|
||||
/// This returns `None` if the cursor is currently pointing to the
|
||||
|
@ -646,14 +646,14 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
///
|
||||
/// // The vector contains no items, even though it has capacity for more
|
||||
/// assert_eq!(vec.len(), 0);
|
||||
/// assert_eq!(vec.capacity(), 10);
|
||||
/// assert!(vec.capacity() >= 10);
|
||||
///
|
||||
/// // These are all done without reallocating...
|
||||
/// for i in 0..10 {
|
||||
/// vec.push(i);
|
||||
/// }
|
||||
/// assert_eq!(vec.len(), 10);
|
||||
/// assert_eq!(vec.capacity(), 10);
|
||||
/// assert!(vec.capacity() >= 10);
|
||||
///
|
||||
/// // ...but this may make the vector reallocate
|
||||
/// vec.push(11);
|
||||
@ -877,7 +877,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// ```
|
||||
/// let mut vec: Vec<i32> = Vec::with_capacity(10);
|
||||
/// vec.push(42);
|
||||
/// assert_eq!(vec.capacity(), 10);
|
||||
/// assert!(vec.capacity() >= 10);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -1028,7 +1028,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// ```
|
||||
/// let mut vec = Vec::with_capacity(10);
|
||||
/// vec.extend([1, 2, 3]);
|
||||
/// assert_eq!(vec.capacity(), 10);
|
||||
/// assert!(vec.capacity() >= 10);
|
||||
/// vec.shrink_to_fit();
|
||||
/// assert!(vec.capacity() >= 3);
|
||||
/// ```
|
||||
@ -1055,7 +1055,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// ```
|
||||
/// let mut vec = Vec::with_capacity(10);
|
||||
/// vec.extend([1, 2, 3]);
|
||||
/// assert_eq!(vec.capacity(), 10);
|
||||
/// assert!(vec.capacity() >= 10);
|
||||
/// vec.shrink_to(4);
|
||||
/// assert!(vec.capacity() >= 4);
|
||||
/// vec.shrink_to(0);
|
||||
@ -1090,7 +1090,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// let mut vec = Vec::with_capacity(10);
|
||||
/// vec.extend([1, 2, 3]);
|
||||
///
|
||||
/// assert_eq!(vec.capacity(), 10);
|
||||
/// assert!(vec.capacity() >= 10);
|
||||
/// let slice = vec.into_boxed_slice();
|
||||
/// assert_eq!(slice.into_vec().capacity(), 3);
|
||||
/// ```
|
||||
|
@ -866,7 +866,7 @@ where
|
||||
///
|
||||
/// A data provider provides values by calling this type's provide methods.
|
||||
#[unstable(feature = "provide_any", issue = "96024")]
|
||||
#[repr(transparent)]
|
||||
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
|
||||
pub struct Demand<'a>(dyn Erased<'a> + 'a);
|
||||
|
||||
impl<'a> Demand<'a> {
|
||||
|
@ -2030,6 +2030,27 @@ impl<T> UnsafeCell<T> {
|
||||
}
|
||||
|
||||
impl<T: ?Sized> UnsafeCell<T> {
|
||||
/// Converts from `&mut T` to `&mut UnsafeCell<T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(unsafe_cell_from_mut)]
|
||||
/// use std::cell::UnsafeCell;
|
||||
///
|
||||
/// let mut val = 42;
|
||||
/// let uc = UnsafeCell::from_mut(&mut val);
|
||||
///
|
||||
/// *uc.get_mut() -= 1;
|
||||
/// assert_eq!(*uc.get_mut(), 41);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
#[unstable(feature = "unsafe_cell_from_mut", issue = "111645")]
|
||||
pub const fn from_mut(value: &mut T) -> &mut UnsafeCell<T> {
|
||||
// SAFETY: `UnsafeCell<T>` has the same memory layout as `T` due to #[repr(transparent)].
|
||||
unsafe { &mut *(value as *mut T as *mut UnsafeCell<T>) }
|
||||
}
|
||||
|
||||
/// Gets a mutable pointer to the wrapped value.
|
||||
///
|
||||
/// This can be cast to a pointer of any kind.
|
||||
|
@ -517,8 +517,6 @@ impl CStr {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(cstr_is_empty)]
|
||||
///
|
||||
/// use std::ffi::CStr;
|
||||
/// # use std::ffi::FromBytesWithNulError;
|
||||
///
|
||||
@ -533,7 +531,8 @@ impl CStr {
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "cstr_is_empty", issue = "102444")]
|
||||
#[stable(feature = "cstr_is_empty", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "cstr_is_empty", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
// SAFETY: We know there is at least one byte; for empty strings it
|
||||
// is the NUL terminator.
|
||||
|
@ -203,7 +203,7 @@ mod c_long_definition {
|
||||
// be UB.
|
||||
#[doc = include_str!("c_void.md")]
|
||||
#[cfg_attr(not(bootstrap), lang = "c_void")]
|
||||
#[repr(u8)]
|
||||
#[cfg_attr(not(doc), repr(u8))] // work around https://github.com/rust-lang/rust/issues/90435
|
||||
#[stable(feature = "core_c_void", since = "1.30.0")]
|
||||
pub enum c_void {
|
||||
#[unstable(
|
||||
@ -244,7 +244,7 @@ impl fmt::Debug for c_void {
|
||||
target_os = "uefi",
|
||||
windows,
|
||||
))]
|
||||
#[repr(transparent)]
|
||||
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
|
||||
#[unstable(
|
||||
feature = "c_variadic",
|
||||
reason = "the `c_variadic` feature has not been properly tested on \
|
||||
@ -296,7 +296,7 @@ impl<'f> fmt::Debug for VaListImpl<'f> {
|
||||
not(target_os = "uefi"),
|
||||
not(windows),
|
||||
))]
|
||||
#[repr(C)]
|
||||
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
|
||||
#[derive(Debug)]
|
||||
#[unstable(
|
||||
feature = "c_variadic",
|
||||
@ -316,7 +316,7 @@ pub struct VaListImpl<'f> {
|
||||
|
||||
/// PowerPC ABI implementation of a `va_list`.
|
||||
#[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))]
|
||||
#[repr(C)]
|
||||
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
|
||||
#[derive(Debug)]
|
||||
#[unstable(
|
||||
feature = "c_variadic",
|
||||
@ -336,7 +336,7 @@ pub struct VaListImpl<'f> {
|
||||
|
||||
/// s390x ABI implementation of a `va_list`.
|
||||
#[cfg(target_arch = "s390x")]
|
||||
#[repr(C)]
|
||||
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
|
||||
#[derive(Debug)]
|
||||
#[unstable(
|
||||
feature = "c_variadic",
|
||||
@ -355,7 +355,7 @@ pub struct VaListImpl<'f> {
|
||||
|
||||
/// x86_64 ABI implementation of a `va_list`.
|
||||
#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))]
|
||||
#[repr(C)]
|
||||
#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
|
||||
#[derive(Debug)]
|
||||
#[unstable(
|
||||
feature = "c_variadic",
|
||||
@ -373,7 +373,7 @@ pub struct VaListImpl<'f> {
|
||||
}
|
||||
|
||||
/// A wrapper for a `va_list`
|
||||
#[repr(transparent)]
|
||||
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
|
||||
#[derive(Debug)]
|
||||
#[unstable(
|
||||
feature = "c_variadic",
|
||||
|
@ -986,6 +986,14 @@ pub trait PointerLike {}
|
||||
#[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")]
|
||||
pub trait ConstParamTy: StructuralEq {}
|
||||
|
||||
/// Derive macro generating an impl of the trait `Copy`.
|
||||
#[rustc_builtin_macro]
|
||||
#[unstable(feature = "adt_const_params", issue = "95174")]
|
||||
#[cfg(not(bootstrap))]
|
||||
pub macro ConstParamTy($item:item) {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
// FIXME(generic_const_parameter_types): handle `ty::FnDef`/`ty::Closure`
|
||||
// FIXME(generic_const_parameter_types): handle `ty::Tuple`
|
||||
marker_impls! {
|
||||
|
@ -393,6 +393,8 @@ use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver};
|
||||
/// value in place, preventing the value referenced by that pointer from being moved
|
||||
/// unless it implements [`Unpin`].
|
||||
///
|
||||
/// `Pin<P>` is guaranteed to have the same memory layout and ABI as `P`.
|
||||
///
|
||||
/// *See the [`pin` module] documentation for an explanation of pinning.*
|
||||
///
|
||||
/// [`pin` module]: self
|
||||
|
@ -232,7 +232,7 @@ impl fmt::Debug for Context<'_> {
|
||||
///
|
||||
/// [`Future::poll()`]: core::future::Future::poll
|
||||
/// [`Poll::Pending`]: core::task::Poll::Pending
|
||||
#[repr(transparent)]
|
||||
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
pub struct Waker {
|
||||
waker: RawWaker,
|
||||
|
@ -88,7 +88,7 @@ impl_element! { isize }
|
||||
/// The layout of this type is unspecified, and may change between platforms
|
||||
/// and/or Rust versions, and code should not assume that it is equivalent to
|
||||
/// `[T; LANES]`.
|
||||
#[repr(transparent)]
|
||||
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
|
||||
pub struct Mask<T, const LANES: usize>(mask_impl::Mask<T, LANES>)
|
||||
where
|
||||
T: MaskElement,
|
||||
|
@ -1751,7 +1751,7 @@ fn render_impl(
|
||||
if trait_.is_none() && i.inner_impl().items.is_empty() {
|
||||
w.write_str(
|
||||
"<div class=\"item-info\">\
|
||||
<div class=\"stab empty-impl\">This impl block contains no items.</div>
|
||||
<div class=\"stab empty-impl\">This impl block contains no items.</div>\
|
||||
</div>",
|
||||
);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet};
|
||||
use rustc_hir::intravisit::{walk_item, Visitor};
|
||||
use rustc_hir::intravisit::{walk_body, walk_item, Visitor};
|
||||
use rustc_hir::{Node, CRATE_HIR_ID};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
@ -106,6 +106,7 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> {
|
||||
exact_paths: DefIdMap<Vec<Symbol>>,
|
||||
modules: Vec<Module<'tcx>>,
|
||||
is_importable_from_parent: bool,
|
||||
inside_body: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
@ -129,6 +130,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
exact_paths: Default::default(),
|
||||
modules: vec![om],
|
||||
is_importable_from_parent: true,
|
||||
inside_body: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,6 +370,26 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
import_id: Option<LocalDefId>,
|
||||
) {
|
||||
debug!("visiting item {:?}", item);
|
||||
if self.inside_body {
|
||||
// Only impls can be "seen" outside a body. For example:
|
||||
//
|
||||
// ```
|
||||
// struct Bar;
|
||||
//
|
||||
// fn foo() {
|
||||
// impl Bar { fn bar() {} }
|
||||
// }
|
||||
// Bar::bar();
|
||||
// ```
|
||||
if let hir::ItemKind::Impl(impl_) = item.kind &&
|
||||
// Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
|
||||
// them up regardless of where they're located.
|
||||
impl_.of_trait.is_none()
|
||||
{
|
||||
self.add_to_current_mod(item, None, None);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let name = renamed.unwrap_or(item.ident.name);
|
||||
let tcx = self.cx.tcx;
|
||||
|
||||
@ -564,4 +586,10 @@ impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> {
|
||||
fn visit_lifetime(&mut self, _: &hir::Lifetime) {
|
||||
// Unneeded.
|
||||
}
|
||||
|
||||
fn visit_body(&mut self, b: &'tcx hir::Body<'tcx>) {
|
||||
let prev = mem::replace(&mut self.inside_body, true);
|
||||
walk_body(self, b);
|
||||
self.inside_body = prev;
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit ea6fa9c2d43aaf0f11559719eda9b54d356d5416
|
||||
Subproject commit 533d3f338b804d54e5d0ac4fba6276af23002d9c
|
@ -1 +1 @@
|
||||
Subproject commit 13413c64ff88dd6c2824e9eb9374fc5f10895d28
|
||||
Subproject commit 09276c703a473ab33daaeb94917232e80eefd628
|
@ -289,10 +289,11 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte
|
||||
let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false };
|
||||
|
||||
match expected_item {
|
||||
Item::Lang(expected_lang_item) => {
|
||||
let expected_id = cx.tcx.lang_items().require(expected_lang_item).unwrap();
|
||||
cx.tcx.parent(id) == expected_id
|
||||
},
|
||||
Item::Lang(expected_lang_item) => cx
|
||||
.tcx
|
||||
.lang_items()
|
||||
.get(expected_lang_item)
|
||||
.map_or(false, |expected_id| cx.tcx.parent(id) == expected_id),
|
||||
Item::Diag(expected_ty, expected_variant) => {
|
||||
let ty = cx.typeck_results().pat_ty(pat);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user