Merge from rustc

This commit is contained in:
The Miri Conjob Bot 2023-09-27 05:48:00 +00:00
commit b1f5c6683b
459 changed files with 8314 additions and 3508 deletions

View file

@ -118,16 +118,15 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.3.2"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is-terminal",
"utf8parse",
]
@ -157,9 +156,9 @@ dependencies = [
[[package]]
name = "anstyle-wincon"
version = "1.0.1"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
dependencies = [
"anstyle",
"windows-sys 0.48.0",
@ -291,9 +290,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.3.3"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "block-buffer"
@ -459,25 +458,23 @@ dependencies = [
[[package]]
name = "clap"
version = "4.3.10"
version = "4.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a"
checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136"
dependencies = [
"clap_builder",
"clap_derive",
"once_cell",
]
[[package]]
name = "clap_builder"
version = "4.3.10"
version = "4.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d"
checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"once_cell",
"strsim",
"terminal_size",
]
@ -493,9 +490,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.3.2"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f"
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
dependencies = [
"heck",
"proc-macro2",
@ -515,7 +512,6 @@ version = "0.1.74"
dependencies = [
"clippy_lints",
"clippy_utils",
"derive-new",
"filetime",
"futures",
"if_chain",
@ -944,17 +940,6 @@ dependencies = [
"syn 2.0.29",
]
[[package]]
name = "derive-new"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "derive_builder"
version = "0.12.0"
@ -1253,12 +1238,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
[[package]]
name = "fastrand"
version = "1.9.0"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
dependencies = [
"instant",
]
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
[[package]]
name = "field-offset"
@ -1993,17 +1975,6 @@ dependencies = [
"unic-langid",
]
[[package]]
name = "io-lifetimes"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi 0.3.2",
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "ipnet"
version = "2.7.2"
@ -2017,7 +1988,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb"
dependencies = [
"hermit-abi 0.3.2",
"rustix 0.38.2",
"rustix",
"windows-sys 0.48.0",
]
@ -2214,15 +2185,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "linux-raw-sys"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"
checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
[[package]]
name = "litemap"
@ -3006,6 +2971,27 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "575fc2d9b3da54adbdfaddf6eca48fec256d977c8630a1750b8991347d1ac911"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]
[[package]]
name = "r-efi-alloc"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7"
dependencies = [
"compiler_builtins",
"r-efi",
"rustc-std-workspace-core",
]
[[package]]
name = "rand"
version = "0.8.5"
@ -3259,6 +3245,7 @@ dependencies = [
"rustc_driver",
"rustc_driver_impl",
"rustc_smir",
"stable_mir",
]
[[package]]
@ -4423,7 +4410,7 @@ dependencies = [
"rustc_session",
"rustc_span",
"rustc_target",
"scoped-tls",
"stable_mir",
"tracing",
]
@ -4690,28 +4677,14 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.37.22"
version = "0.38.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c"
checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f"
dependencies = [
"bitflags 1.3.2",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys 0.3.8",
"windows-sys 0.48.0",
]
[[package]]
name = "rustix"
version = "0.38.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aabcb0461ebd01d6b79945797c27f8529082226cb630a9865a71870ff63532a4"
dependencies = [
"bitflags 2.3.3",
"bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys 0.4.3",
"linux-raw-sys",
"windows-sys 0.48.0",
]
@ -4974,6 +4947,14 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "stable_mir"
version = "0.1.0-preview"
dependencies = [
"scoped-tls",
"tracing",
]
[[package]]
name = "stacker"
version = "0.1.15"
@ -5012,6 +4993,8 @@ dependencies = [
"panic_abort",
"panic_unwind",
"profiler_builtins",
"r-efi",
"r-efi-alloc",
"rand",
"rand_xorshift",
"rustc-demangle",
@ -5173,15 +5156,14 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.6.0"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6"
checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
dependencies = [
"autocfg",
"cfg-if",
"fastrand",
"redox_syscall 0.3.5",
"rustix 0.37.22",
"rustix",
"windows-sys 0.48.0",
]
@ -5218,11 +5200,11 @@ dependencies = [
[[package]]
name = "terminal_size"
version = "0.2.6"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
dependencies = [
"rustix 0.37.22",
"rustix",
"windows-sys 0.48.0",
]

View file

@ -13,6 +13,7 @@ rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
# Make sure rustc_smir ends up in the sysroot, because this
# crate is intended to be used by stable MIR consumers, which are not in-tree
rustc_smir = { path = "../rustc_smir" }
stable_mir = { path = "../stable_mir" }
[dependencies.jemalloc-sys]
version = "0.5.0"

View file

@ -37,9 +37,10 @@ use std::ptr::{self, NonNull};
use std::slice;
use std::{cmp, intrinsics};
/// This calls the passed function while ensuring it won't be inlined into the caller.
#[inline(never)]
#[cold]
fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
fn outline<F: FnOnce() -> R, R>(f: F) -> R {
f()
}
@ -600,7 +601,7 @@ impl DroplessArena {
unsafe { self.write_from_iter(iter, len, mem) }
}
(_, _) => {
cold_path(move || -> &mut [T] {
outline(move || -> &mut [T] {
let mut vec: SmallVec<[_; 8]> = iter.collect();
if vec.is_empty() {
return &mut [];

View file

@ -1664,7 +1664,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
lifetime.ident,
));
// Now make an arg that we can use for the substs of the opaque tykind.
// Now make an arg that we can use for the generic params of the opaque tykind.
let id = self.next_node_id();
let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res);
let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id);

View file

@ -578,11 +578,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
}
}
// All uses of `gate_all!` below this point were added in #65742,
// All uses of `gate_all_legacy_dont_use!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).
// We emit an early future-incompatible warning for these.
// New syntax gates should go above here to get a hard error gate.
macro_rules! gate_all {
macro_rules! gate_all_legacy_dont_use {
($gate:ident, $msg:literal) => {
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg);
@ -590,13 +590,19 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
};
}
gate_all!(trait_alias, "trait aliases are experimental");
gate_all!(associated_type_bounds, "associated type bounds are unstable");
gate_all!(return_type_notation, "return type notation is experimental");
gate_all!(decl_macro, "`macro` is experimental");
gate_all!(box_patterns, "box pattern syntax is experimental");
gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
gate_all!(try_blocks, "`try` blocks are unstable");
gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
gate_all_legacy_dont_use!(associated_type_bounds, "associated type bounds are unstable");
// Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
// used to be gated under associated_type_bounds, which are right above, so RTN needs to
// be too.
gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental");
gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
gate_all_legacy_dont_use!(
exclusive_range_pattern,
"exclusive range pattern syntax is experimental"
);
gate_all_legacy_dont_use!(try_blocks, "`try` blocks are unstable");
visit::walk_crate(&mut visitor, krate);
}

View file

@ -27,7 +27,7 @@ pub(crate) struct RegionName {
/// This helps to print the right kinds of diagnostics.
#[derive(Debug, Clone)]
pub(crate) enum RegionNameSource {
/// A bound (not free) region that was substituted at the def site (not an HRTB).
/// A bound (not free) region that was instantiated at the def site (not an HRTB).
NamedEarlyBoundRegion(Span),
/// A free region that the user has a name (`'a`) for.
NamedFreeRegion(Span),
@ -354,7 +354,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
})
}
ty::BoundRegionKind::BrAnon(..) => None,
ty::BoundRegionKind::BrAnon => None,
},
ty::ReLateBound(..)
@ -516,7 +516,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
// be the same as those of the ADT.
// FIXME: We should be able to do something similar to
// match_adt_and_segment in this case.
Res::Def(DefKind::TyAlias { .. }, _) => (),
Res::Def(DefKind::TyAlias, _) => (),
_ => {
if let Some(last_segment) = path.segments.last() {
if let Some(highlight) = self.match_adt_and_segment(
@ -619,7 +619,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
// programs, so we need to use delay_span_bug here. See #82126.
self.infcx.tcx.sess.delay_span_bug(
hir_arg.span(),
format!("unmatched subst and hir arg: found {kind:?} vs {hir_arg:?}"),
format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"),
);
}
}

View file

@ -2250,7 +2250,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
// Query canonicalization can create local superuniverses (for example in
// `InferCtx::query_response_substitution_guess`), but they don't have an associated
// `InferCtx::query_response_instantiation_guess`), but they don't have an associated
// `UniverseInfo` explaining why they were created.
// This can cause ICEs if these causes are accessed in diagnostics, for example in issue
// #114907 where this happens via liveness and dropck outlives results.

View file

@ -7,7 +7,7 @@ use rustc_middle::mir::visit::{MutVisitor, TyContext};
use rustc_middle::mir::{Body, ConstOperand, Location, Promoted};
use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_span::{Span, Symbol};
use rustc_span::Symbol;
/// Replaces all free regions appearing in the MIR with fresh
/// inference variables, returning the number of variables created.
@ -28,21 +28,15 @@ pub fn renumber_mir<'tcx>(
renumberer.visit_body(body);
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) enum BoundRegionInfo {
Name(Symbol),
Span(Span),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) enum RegionCtxt {
Location(Location),
TyContext(TyContext),
Free(Symbol),
Bound(BoundRegionInfo),
LateBound(BoundRegionInfo),
Bound(Symbol),
LateBound(Symbol),
Existential(Option<Symbol>),
Placeholder(BoundRegionInfo),
Placeholder(Symbol),
Unknown,
}

View file

@ -1007,7 +1007,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
pub(super) fn register_predefined_opaques_in_new_solver(&mut self) {
// OK to use the identity substitutions for each opaque type key, since
// OK to use the identity arguments for each opaque type key, since
// we remap opaques from HIR typeck back to their definition params.
let opaques: Vec<_> = self
.infcx
@ -1367,14 +1367,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
};
let (sig, map) = tcx.replace_late_bound_regions(sig, |br| {
use crate::renumber::{BoundRegionInfo, RegionCtxt};
use crate::renumber::RegionCtxt;
let region_ctxt_fn = || {
let reg_info = match br.kind {
ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span),
ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(sym::anon),
ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name),
ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env),
ty::BoundRegionKind::BrAnon => sym::anon,
ty::BoundRegionKind::BrNamed(_, name) => name,
ty::BoundRegionKind::BrEnv => sym::env,
};
RegionCtxt::LateBound(reg_info)

View file

@ -11,7 +11,7 @@ use rustc_span::{Span, Symbol};
use crate::constraints::OutlivesConstraint;
use crate::diagnostics::UniverseInfo;
use crate::renumber::{BoundRegionInfo, RegionCtxt};
use crate::renumber::RegionCtxt;
use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker};
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
@ -126,10 +126,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
.placeholder_region(self.type_checker.infcx, placeholder);
let reg_info = match placeholder.bound.kind {
ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span),
ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(sym::anon),
ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name),
ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env),
ty::BoundRegionKind::BrAnon => sym::anon,
ty::BoundRegionKind::BrNamed(_, name) => name,
ty::BoundRegionKind::BrEnv => sym::env,
};
if cfg!(debug_assertions) {

View file

@ -28,7 +28,7 @@ use rustc_span::symbol::{kw, sym};
use rustc_span::Symbol;
use std::iter;
use crate::renumber::{BoundRegionInfo, RegionCtxt};
use crate::renumber::RegionCtxt;
use crate::BorrowckInferCtxt;
#[derive(Debug)]
@ -446,9 +446,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
if !indices.indices.contains_key(&r) {
let region_vid = {
let name = r.get_name_or_anon();
self.infcx.next_nll_region_var(FR, || {
RegionCtxt::LateBound(BoundRegionInfo::Name(name))
})
self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
};
debug!(?region_vid);
@ -480,9 +478,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
if !indices.indices.contains_key(&r) {
let region_vid = {
let name = r.get_name_or_anon();
self.infcx.next_nll_region_var(FR, || {
RegionCtxt::LateBound(BoundRegionInfo::Name(name))
})
self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
};
debug!(?region_vid);
@ -643,10 +639,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
};
let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
let subst_mapping =
iter::zip(identity_args.regions(), fr_args.regions().map(|r| r.as_var()));
let arg_mapping = iter::zip(identity_args.regions(), fr_args.regions().map(|r| r.as_var()));
UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect(), fr_static }
UniversalRegionIndices { indices: global_mapping.chain(arg_mapping).collect(), fr_static }
}
fn compute_inputs_and_output(
@ -796,7 +791,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
_ => sym::anon,
};
self.next_nll_region_var(origin, || RegionCtxt::Bound(BoundRegionInfo::Name(name)))
self.next_nll_region_var(origin, || RegionCtxt::Bound(name))
};
indices.insert_late_bound_region(liberated_region, region_vid.as_var());
@ -826,9 +821,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
if !indices.indices.contains_key(&r) {
let region_vid = {
let name = r.get_name_or_anon();
self.next_nll_region_var(FR, || {
RegionCtxt::LateBound(BoundRegionInfo::Name(name))
})
self.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
};
debug!(?region_vid);
@ -848,9 +841,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
if !indices.indices.contains_key(&r) {
let region_vid = {
let name = r.get_name_or_anon();
self.next_nll_region_var(FR, || {
RegionCtxt::LateBound(BoundRegionInfo::Name(name))
})
self.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
};
indices.insert_late_bound_region(r, region_vid.as_var());

View file

@ -41,7 +41,7 @@ pub fn expand_deriving_const_param_ty(
path: path_std!(marker::ConstParamTy),
skip_path_as_bound: false,
needs_copy_as_bound_if_packed: false,
additional_bounds: Vec::new(),
additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))],
supports_unions: false,
methods: Vec::new(),
associated_types: Vec::new(),

View file

@ -100,9 +100,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
stack = &stack[..index + ENCODE_METADATA.len()];
}
const SUBST_AND_NORMALIZE_ERASING_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::subst_and_normalize_erasing_regions";
if let Some(index) = stack.find(SUBST_AND_NORMALIZE_ERASING_REGIONS) {
stack = &stack[..index + SUBST_AND_NORMALIZE_ERASING_REGIONS.len()];
const INSTANTIATE_AND_NORMALIZE_ERASING_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::instantiate_and_normalize_erasing_regions";
if let Some(index) = stack.find(INSTANTIATE_AND_NORMALIZE_ERASING_REGIONS) {
stack = &stack[..index + INSTANTIATE_AND_NORMALIZE_ERASING_REGIONS.len()];
}
const NORMALIZE_ERASING_LATE_BOUND_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::normalize_erasing_late_bound_regions";

View file

@ -359,7 +359,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
{
self.instance.subst_mir_and_normalize_erasing_regions(
self.instance.instantiate_mir_and_normalize_erasing_regions(
self.tcx,
ty::ParamEnv::reveal_all(),
ty::EarlyBinder::bind(value),

View file

@ -0,0 +1,103 @@
use std::{
ffi::{c_char, CStr},
marker::PhantomData,
ops::Deref,
ptr::NonNull,
};
use rustc_data_structures::small_c_str::SmallCStr;
use crate::{errors::LlvmError, llvm};
/// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions.
/// Not cloneable as there is no clone function for llvm::TargetMachine.
#[repr(transparent)]
pub struct OwnedTargetMachine {
tm_unique: NonNull<llvm::TargetMachine>,
phantom: PhantomData<llvm::TargetMachine>,
}
impl OwnedTargetMachine {
pub fn new(
triple: &CStr,
cpu: &CStr,
features: &CStr,
abi: &CStr,
model: llvm::CodeModel,
reloc: llvm::RelocModel,
level: llvm::CodeGenOptLevel,
use_soft_fp: bool,
function_sections: bool,
data_sections: bool,
unique_section_names: bool,
trap_unreachable: bool,
singletree: bool,
asm_comments: bool,
emit_stack_size_section: bool,
relax_elf_relocations: bool,
use_init_array: bool,
split_dwarf_file: &CStr,
output_obj_file: &CStr,
debug_info_compression: &CStr,
force_emulated_tls: bool,
args_cstr_buff: &[u8],
) -> Result<Self, LlvmError<'static>> {
assert!(args_cstr_buff.len() > 0);
assert!(
*args_cstr_buff.last().unwrap() == 0,
"The last character must be a null terminator."
);
// SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data
let tm_ptr = unsafe {
llvm::LLVMRustCreateTargetMachine(
triple.as_ptr(),
cpu.as_ptr(),
features.as_ptr(),
abi.as_ptr(),
model,
reloc,
level,
use_soft_fp,
function_sections,
data_sections,
unique_section_names,
trap_unreachable,
singletree,
asm_comments,
emit_stack_size_section,
relax_elf_relocations,
use_init_array,
split_dwarf_file.as_ptr(),
output_obj_file.as_ptr(),
debug_info_compression.as_ptr(),
force_emulated_tls,
args_cstr_buff.as_ptr() as *const c_char,
args_cstr_buff.len(),
)
};
NonNull::new(tm_ptr)
.map(|tm_unique| Self { tm_unique, phantom: PhantomData })
.ok_or_else(|| LlvmError::CreateTargetMachine { triple: SmallCStr::from(triple) })
}
}
impl Deref for OwnedTargetMachine {
type Target = llvm::TargetMachine;
fn deref(&self) -> &Self::Target {
// SAFETY: constructing ensures we have a valid pointer created by llvm::LLVMRustCreateTargetMachine
unsafe { self.tm_unique.as_ref() }
}
}
impl Drop for OwnedTargetMachine {
fn drop(&mut self) {
// SAFETY: constructing ensures we have a valid pointer created by llvm::LLVMRustCreateTargetMachine
// OwnedTargetMachine is not copyable so there is no double free or use after free
unsafe {
llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_mut());
}
}
}

View file

@ -1,4 +1,5 @@
use crate::back::lto::ThinBuffer;
use crate::back::owned_target_machine::OwnedTargetMachine;
use crate::back::profiling::{
selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler,
};
@ -98,8 +99,8 @@ pub fn write_output_file<'ll>(
}
}
pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm::TargetMachine {
let config = TargetMachineFactoryConfig { split_dwarf_file: None };
pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine {
let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None };
// Can't use query system here quite yet because this function is invoked before the query
// system/tcx is set up.
let features = llvm_util::global_llvm_features(sess, false);
@ -107,7 +108,7 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm:
.unwrap_or_else(|err| llvm_err(sess.diagnostic(), err).raise())
}
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTargetMachine {
let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
tcx.output_filenames(()).split_dwarf_path(
tcx.sess.split_debuginfo(),
@ -117,7 +118,11 @@ pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut ll
} else {
None
};
let config = TargetMachineFactoryConfig { split_dwarf_file };
let output_obj_file =
Some(tcx.output_filenames(()).temp_path(OutputType::Object, Some(mod_name)));
let config = TargetMachineFactoryConfig { split_dwarf_file, output_obj_file };
target_machine_factory(
&tcx.sess,
tcx.backend_optimization_level(()),
@ -255,38 +260,38 @@ pub fn target_machine_factory(
let debuginfo_compression = SmallCStr::new(&debuginfo_compression);
Arc::new(move |config: TargetMachineFactoryConfig| {
let split_dwarf_file =
path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0;
let split_dwarf_file = CString::new(split_dwarf_file.to_str().unwrap()).unwrap();
let tm = unsafe {
llvm::LLVMRustCreateTargetMachine(
triple.as_ptr(),
cpu.as_ptr(),
features.as_ptr(),
abi.as_ptr(),
code_model,
reloc_model,
opt_level,
use_softfp,
ffunction_sections,
fdata_sections,
funique_section_names,
trap_unreachable,
singlethread,
asm_comments,
emit_stack_size_section,
relax_elf_relocations,
use_init_array,
split_dwarf_file.as_ptr(),
debuginfo_compression.as_ptr(),
force_emulated_tls,
args_cstr_buff.as_ptr() as *const c_char,
args_cstr_buff.len(),
)
let path_to_cstring_helper = |path: Option<PathBuf>| -> CString {
let path = path_mapping.map_prefix(path.unwrap_or_default()).0;
CString::new(path.to_str().unwrap()).unwrap()
};
tm.ok_or_else(|| LlvmError::CreateTargetMachine { triple: triple.clone() })
let split_dwarf_file = path_to_cstring_helper(config.split_dwarf_file);
let output_obj_file = path_to_cstring_helper(config.output_obj_file);
OwnedTargetMachine::new(
&triple,
&cpu,
&features,
&abi,
code_model,
reloc_model,
opt_level,
use_softfp,
ffunction_sections,
fdata_sections,
funique_section_names,
trap_unreachable,
singlethread,
asm_comments,
emit_stack_size_section,
relax_elf_relocations,
use_init_array,
&split_dwarf_file,
&output_obj_file,
&debuginfo_compression,
force_emulated_tls,
&args_cstr_buff,
)
})
}

View file

@ -160,9 +160,9 @@ pub unsafe fn create_module<'ll>(
// Ensure the data-layout values hardcoded remain the defaults.
if sess.target.is_builtin {
// tm is disposed by its drop impl
let tm = crate::back::write::create_informational_target_machine(tcx.sess);
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm);
llvm::LLVMRustDisposeTargetMachine(tm);
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
let llvm_data_layout = llvm::LLVMGetDataLayoutStr(llmod);
let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes())

View file

@ -90,7 +90,7 @@ fn make_mir_scope<'ll, 'tcx>(
Some((callee, _)) => {
// FIXME(eddyb) this would be `self.monomorphize(&callee)`
// if this is moved to `rustc_codegen_ssa::mir::debuginfo`.
let callee = cx.tcx.subst_and_normalize_erasing_regions(
let callee = cx.tcx.instantiate_and_normalize_erasing_regions(
instance.args,
ty::ParamEnv::reveal_all(),
ty::EarlyBinder::bind(callee),

View file

@ -529,7 +529,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
if let Some(impl_def_id) = cx.tcx.impl_of_method(instance.def_id()) {
// If the method does *not* belong to a trait, proceed
if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions(
let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
instance.args,
ty::ParamEnv::reveal_all(),
cx.tcx.type_of(impl_def_id),

View file

@ -22,6 +22,7 @@ extern crate rustc_macros;
#[macro_use]
extern crate tracing;
use back::owned_target_machine::OwnedTargetMachine;
use back::write::{create_informational_target_machine, create_target_machine};
use errors::ParseTargetMachineConfig;
@ -52,6 +53,7 @@ use std::io::Write;
mod back {
pub mod archive;
pub mod lto;
pub mod owned_target_machine;
mod profiling;
pub mod write;
}
@ -162,7 +164,7 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
impl WriteBackendMethods for LlvmCodegenBackend {
type Module = ModuleLlvm;
type ModuleBuffer = back::lto::ModuleBuffer;
type TargetMachine = &'static mut llvm::TargetMachine;
type TargetMachine = OwnedTargetMachine;
type TargetMachineError = crate::errors::LlvmError<'static>;
type ThinData = back::lto::ThinData;
type ThinBuffer = back::lto::ThinBuffer;
@ -401,7 +403,9 @@ impl CodegenBackend for LlvmCodegenBackend {
pub struct ModuleLlvm {
llcx: &'static mut llvm::Context,
llmod_raw: *const llvm::Module,
tm: &'static mut llvm::TargetMachine,
// independent from llcx and llmod_raw, resources get disposed by drop impl
tm: OwnedTargetMachine,
}
unsafe impl Send for ModuleLlvm {}
@ -453,7 +457,6 @@ impl ModuleLlvm {
impl Drop for ModuleLlvm {
fn drop(&mut self) {
unsafe {
llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
}
}

View file

@ -2112,6 +2112,8 @@ extern "C" {
);
pub fn LLVMRustGetHostCPUName(len: *mut usize) -> *const c_char;
// This function makes copies of pointed to data, so the data's lifetime may end after this function returns
pub fn LLVMRustCreateTargetMachine(
Triple: *const c_char,
CPU: *const c_char,
@ -2131,13 +2133,14 @@ extern "C" {
RelaxELFRelocations: bool,
UseInitArray: bool,
SplitDwarfFile: *const c_char,
OutputObjFile: *const c_char,
DebugInfoCompression: *const c_char,
ForceEmulatedTls: bool,
ArgsCstrBuff: *const c_char,
ArgsCstrBuffLen: usize,
) -> Option<&'static mut TargetMachine>;
) -> *mut TargetMachine;
pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
pub fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine);
pub fn LLVMRustAddLibraryInfo<'a>(
PM: &PassManager<'a>,
M: &'a Module,

View file

@ -303,7 +303,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
// check that all features in a given smallvec are enabled
for llvm_feature in to_llvm_features(sess, feature) {
let cstr = SmallCStr::new(llvm_feature);
if !unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } {
if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
return false;
}
}
@ -422,14 +422,14 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess
}
unsafe {
llvm::LLVMRustPrintTargetCPUs(
tm,
&tm,
cpu_cstring.as_ptr(),
callback,
&mut out as *mut &mut dyn PrintBackendInfo as *mut c_void,
);
}
}
PrintKind::TargetFeatures => print_target_features(out, sess, tm),
PrintKind::TargetFeatures => print_target_features(out, sess, &tm),
_ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
}
}

View file

@ -286,6 +286,10 @@ pub struct TargetMachineFactoryConfig {
/// so the path to the dwarf object has to be provided when we create the target machine.
/// This can be ignored by backends which do not need it for their Split DWARF support.
pub split_dwarf_file: Option<PathBuf>,
/// The name of the output object file. Used for setting OutputFilenames in target options
/// so that LLVM can emit the CodeView S_OBJNAME record in pdb files
pub output_obj_file: Option<PathBuf>,
}
impl TargetMachineFactoryConfig {
@ -302,7 +306,10 @@ impl TargetMachineFactoryConfig {
} else {
None
};
TargetMachineFactoryConfig { split_dwarf_file }
let output_obj_file =
Some(cgcx.output_filenames.temp_path(OutputType::Object, Some(module_name)));
TargetMachineFactoryConfig { split_dwarf_file, output_obj_file }
}
}

View file

@ -420,9 +420,11 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
rust_main_def_id: DefId,
entry_type: EntryFnType,
) -> Bx::Function {
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
// depending on whether the target needs `argc` and `argv` to be passed in.
let llfty = if cx.sess().target.main_needs_argc_argv {
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`, or
// `usize efi_main(void *handle, void *system_table)` depending on the target.
let llfty = if cx.sess().target.os.contains("uefi") {
cx.type_func(&[cx.type_ptr(), cx.type_ptr()], cx.type_isize())
} else if cx.sess().target.main_needs_argc_argv {
cx.type_func(&[cx.type_int(), cx.type_ptr()], cx.type_int())
} else {
cx.type_func(&[], cx.type_int())
@ -485,8 +487,12 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
};
let result = bx.call(start_ty, None, None, start_fn, &args, None);
let cast = bx.intcast(result, cx.type_int(), true);
bx.ret(cast);
if cx.sess().target.os.contains("uefi") {
bx.ret(result);
} else {
let cast = bx.intcast(result, cx.type_int(), true);
bx.ret(cast);
}
llfn
}
@ -497,7 +503,17 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
cx: &'a Bx::CodegenCx,
bx: &mut Bx,
) -> (Bx::Value, Bx::Value) {
if cx.sess().target.main_needs_argc_argv {
if cx.sess().target.os.contains("uefi") {
// Params for UEFI
let param_handle = bx.get_param(0);
let param_system_table = bx.get_param(1);
let arg_argc = bx.const_int(cx.type_isize(), 2);
let arg_argv = bx.alloca(cx.type_array(cx.type_ptr(), 2), Align::ONE);
bx.store(param_handle, arg_argv, Align::ONE);
let arg_argv_el1 = bx.gep(cx.type_ptr(), arg_argv, &[bx.const_int(cx.type_int(), 1)]);
bx.store(param_system_table, arg_argv_el1, Align::ONE);
(arg_argc, arg_argv)
} else if cx.sess().target.main_needs_argc_argv {
// Params from native `main()` used as args for rust start function
let param_argc = bx.get_param(0);
let param_argv = bx.get_param(1);

View file

@ -118,7 +118,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
T: Copy + TypeFoldable<TyCtxt<'tcx>>,
{
debug!("monomorphize: self.instance={:?}", self.instance);
self.instance.subst_mir_and_normalize_erasing_regions(
self.instance.instantiate_mir_and_normalize_erasing_regions(
self.cx.tcx(),
ty::ParamEnv::reveal_all(),
ty::EarlyBinder::bind(value),

View file

@ -135,15 +135,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
assert_eq!(alloc_align, layout.align.abi);
let read_scalar = |start, size, s: abi::Scalar, ty| {
let val = alloc
.0
.read_scalar(
bx,
alloc_range(start, size),
/*read_provenance*/ matches!(s.primitive(), abi::Pointer(_)),
)
.unwrap();
bx.scalar_to_backend(val, s, ty)
match alloc.0.read_scalar(
bx,
alloc_range(start, size),
/*read_provenance*/ matches!(s.primitive(), abi::Pointer(_)),
) {
Ok(val) => bx.scalar_to_backend(val, s, ty),
Err(_) => bx.const_poison(ty),
}
};
// It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point.
@ -156,7 +155,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
Abi::Scalar(s @ abi::Scalar::Initialized { .. }) => {
let size = s.size(bx);
assert_eq!(size, layout.size, "abi::Scalar size does not match layout size");
let val = read_scalar(Size::ZERO, size, s, bx.type_ptr());
let val = read_scalar(offset, size, s, bx.backend_type(layout));
OperandRef { val: OperandValue::Immediate(val), layout }
}
Abi::ScalarPair(
@ -164,10 +163,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
b @ abi::Scalar::Initialized { .. },
) => {
let (a_size, b_size) = (a.size(bx), b.size(bx));
let b_offset = a_size.align_to(b.align(bx).abi);
let b_offset = (offset + a_size).align_to(b.align(bx).abi);
assert!(b_offset.bytes() > 0);
let a_val = read_scalar(
Size::ZERO,
offset,
a_size,
a,
bx.scalar_pair_element_backend_type(layout, 0, true),

View file

@ -569,7 +569,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> Result<T, ErrorHandled> {
frame
.instance
.try_subst_mir_and_normalize_erasing_regions(
.try_instantiate_mir_and_normalize_erasing_regions(
*self.tcx,
self.param_env,
ty::EarlyBinder::bind(value),

View file

@ -4,7 +4,7 @@ use rustc_middle::ty::{
};
use std::ops::ControlFlow;
/// Checks whether a type contains generic parameters which require substitution.
/// Checks whether a type contains generic parameters which must be instantiated.
///
/// In case it does, returns a `TooGeneric` const eval error. Note that due to polymorphization
/// types may be "concrete enough" even though they still contain generic parameters in
@ -43,7 +43,8 @@ where
.try_into()
.expect("more generic parameters than can fit into a `u32`");
// Only recurse when generic parameters in fns, closures and generators
// are used and require substitution.
// are used and have to be instantiated.
//
// Just in case there are closures or generators within this subst,
// recurse.
if unused_params.is_used(index) && subst.has_param() {

View file

@ -558,8 +558,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
}
}
/// A faster version of the validation pass that only checks those things which may break when apply
/// generic substitutions.
/// A faster version of the validation pass that only checks those things which may break when
/// instantiating any generic parameters.
pub fn validate_types<'tcx>(
tcx: TyCtxt<'tcx>,
mir_phase: MirPhase,

View file

@ -51,9 +51,10 @@ use std::fmt;
pub use rustc_index::static_assert_size;
/// This calls the passed function while ensuring it won't be inlined into the caller.
#[inline(never)]
#[cold]
pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
pub fn outline<F: FnOnce() -> R, R>(f: F) -> R {
f()
}

View file

@ -81,8 +81,8 @@
//!
//! [mm]: https://github.com/rust-lang/measureme/
use crate::cold_path;
use crate::fx::FxHashMap;
use crate::outline;
use std::borrow::Borrow;
use std::collections::hash_map::Entry;
@ -697,7 +697,7 @@ impl<'a> TimingGuard<'a> {
#[inline]
pub fn finish_with_query_invocation_id(self, query_invocation_id: QueryInvocationId) {
if let Some(guard) = self.0 {
cold_path(|| {
outline(|| {
let event_id = StringId::new_virtual(query_invocation_id.0);
let event_id = EventId::from_virtual(event_id);
guard.finish_with_override_event_id(event_id);

View file

@ -79,3 +79,9 @@ impl<'a> FromIterator<&'a str> for SmallCStr {
Self { data }
}
}
impl From<&ffi::CStr> for SmallCStr {
fn from(s: &ffi::CStr) -> Self {
Self { data: SmallVec::from_slice(s.to_bytes()) }
}
}

View file

@ -6,7 +6,7 @@ use std::ptr;
use std::sync::Arc;
#[cfg(parallel_compiler)]
use {crate::cold_path, crate::sync::CacheAligned};
use {crate::outline, crate::sync::CacheAligned};
/// A pointer to the `RegistryData` which uniquely identifies a registry.
/// This identifier can be reused if the registry gets freed.
@ -25,11 +25,7 @@ impl RegistryId {
fn verify(self) -> usize {
let (id, index) = THREAD_DATA.with(|data| (data.registry_id.get(), data.index.get()));
if id == self {
index
} else {
cold_path(|| panic!("Unable to verify registry association"))
}
if id == self { index } else { outline(|| panic!("Unable to verify registry association")) }
}
}

View file

@ -162,14 +162,13 @@ fn foo<T>(x: T) {
```
The machine code for `foo::<u8>()`, `foo::<bool>()`, `foo::<String>()`, or any
other type substitution is different. Hence the compiler generates the
other instantiation is different. Hence the compiler generates the
implementation on-demand. If you call `foo()` with a `bool` parameter, the
compiler will only generate code for `foo::<bool>()`. When we have additional
type parameters, the number of monomorphized implementations the compiler
generates does not grow drastically, since the compiler will only generate an
implementation if the function is called with unparameterized substitutions
(i.e., substitutions where none of the substituted types are themselves
parameterized).
implementation if the function is called with fully concrete arguments
(i.e., arguments which do not contain any generic parameters).
However, with trait objects we have to make a table containing _every_ object
that implements the trait. Now, if it has type parameters, we need to add

View file

@ -3,7 +3,7 @@ An invalid number of generic parameters was passed to an intrinsic function.
Erroneous code example:
```compile_fail,E0094
#![feature(intrinsics)]
#![feature(intrinsics, rustc_attrs)]
#![allow(internal_features)]
extern "rust-intrinsic" {
@ -18,7 +18,7 @@ and verify with the function declaration in the Rust source code.
Example:
```
#![feature(intrinsics)]
#![feature(intrinsics, rustc_attrs)]
#![allow(internal_features)]
extern "rust-intrinsic" {

View file

@ -4,7 +4,7 @@ You used a function or type which doesn't fit the requirements for where it was
used. Erroneous code examples:
```compile_fail
#![feature(intrinsics)]
#![feature(intrinsics, rustc_attrs)]
#![allow(internal_features)]
extern "rust-intrinsic" {
@ -41,7 +41,7 @@ impl Foo {
For the first code example, please check the function definition. Example:
```
#![feature(intrinsics)]
#![feature(intrinsics, rustc_attrs)]
#![allow(internal_features)]
extern "rust-intrinsic" {

View file

@ -537,7 +537,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
"allow_internal_unsafe side-steps the unsafe_code lint",
),
ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk),
rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing,
"rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
through unstable paths"),
@ -806,6 +805,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
r#"`rustc_doc_primitive` is a rustc internal attribute"#,
),
rustc_attr!(
rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing,
"the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe"
),
// ==========================================================================
// Internal attributes, Testing:

View file

@ -61,9 +61,7 @@ pub enum DefKind {
Variant,
Trait,
/// Type alias: `type Foo = Bar;`
TyAlias {
lazy: bool,
},
TyAlias,
/// Type from an `extern` block.
ForeignTy,
/// Trait alias: `trait IntIterator = Iterator<Item = i32>;`
@ -143,7 +141,7 @@ impl DefKind {
DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) => "tuple struct",
DefKind::Ctor(CtorOf::Struct, CtorKind::Const) => "unit struct",
DefKind::OpaqueTy => "opaque type",
DefKind::TyAlias { .. } => "type alias",
DefKind::TyAlias => "type alias",
DefKind::TraitAlias => "trait alias",
DefKind::AssocTy => "associated type",
DefKind::Union => "union",
@ -199,7 +197,7 @@ impl DefKind {
| DefKind::Variant
| DefKind::Trait
| DefKind::OpaqueTy
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
@ -250,7 +248,7 @@ impl DefKind {
| DefKind::Enum
| DefKind::Variant
| DefKind::Trait
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy

View file

@ -101,7 +101,7 @@ impl Target {
DefKind::Mod => Target::Mod,
DefKind::ForeignMod => Target::ForeignMod,
DefKind::GlobalAsm => Target::GlobalAsm,
DefKind::TyAlias { .. } => Target::TyAlias,
DefKind::TyAlias => Target::TyAlias,
DefKind::OpaqueTy => Target::OpaqueTy,
DefKind::Enum => Target::Enum,
DefKind::Struct => Target::Struct,

View file

@ -427,7 +427,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let bound_vars = tcx.late_bound_vars(binding.hir_id);
ty::Binder::bind_with_vars(subst_output, bound_vars)
} else {
// Include substitutions for generic parameters of associated types
// Append the generic arguments of the associated type to the `trait_ref`.
candidate.map_bound(|trait_ref| {
let ident = Ident::new(assoc_item.name, binding.item_name.span);
let item_segment = hir::PathSegment {

View file

@ -139,22 +139,22 @@ fn generic_arg_mismatch_err(
err.emit()
}
/// Creates the relevant generic argument substitutions
/// Creates the relevant generic arguments
/// corresponding to a set of generic parameters. This is a
/// rather complex function. Let us try to explain the role
/// of each of its parameters:
///
/// To start, we are given the `def_id` of the thing we are
/// creating the substitutions for, and a partial set of
/// substitutions `parent_args`. In general, the substitutions
/// for an item begin with substitutions for all the "parents" of
/// To start, we are given the `def_id` of the thing whose generic
/// parameters we are instantiating, and a partial set of
/// arguments `parent_args`. In general, the generic arguments
/// for an item begin with arguments for all the "parents" of
/// that item -- e.g., for a method it might include the
/// parameters from the impl.
///
/// Therefore, the method begins by walking down these parents,
/// starting with the outermost parent and proceed inwards until
/// it reaches `def_id`. For each parent `P`, it will check `parent_args`
/// first to see if the parent's substitutions are listed in there. If so,
/// first to see if the parent's arguments are listed in there. If so,
/// we can append those and move on. Otherwise, it invokes the
/// three callback functions:
///
@ -188,7 +188,7 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
stack.push((def_id, parent_defs));
}
// We manually build up the substitution, rather than using convenience
// We manually build up the generic arguments, rather than using convenience
// methods in `subst.rs`, so that we can iterate over the arguments and
// parameters in lock-step linearly, instead of trying to match each pair.
let mut args: SmallVec<[ty::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
@ -196,7 +196,8 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
while let Some((def_id, defs)) = stack.pop() {
let mut params = defs.params.iter().peekable();
// If we have already computed substitutions for parents, we can use those directly.
// If we have already computed the generic arguments for parents,
// we can use those directly.
while let Some(&param) = params.peek() {
if let Some(&kind) = parent_args.get(param.index as usize) {
args.push(kind);

View file

@ -289,7 +289,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
/// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
/// returns an appropriate set of substitutions for this particular reference to `I`.
/// returns an appropriate set of generic arguments for this particular reference to `I`.
pub fn ast_path_args_for_ty(
&self,
span: Span,
@ -315,7 +315,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Given the type/lifetime/const arguments provided to some path (along with
/// an implicit `Self`, if this is a trait reference), returns the complete
/// set of substitutions. This may involve applying defaulted type parameters.
/// set of generic arguments. This may involve applying defaulted type parameters.
/// Constraints on associated types are created from `create_assoc_bindings_for_generic_args`.
///
/// Example:
@ -909,23 +909,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let tcx = self.tcx();
let args = self.ast_path_args_for_ty(span, did, item_segment);
if let DefKind::TyAlias { lazy: true } = tcx.def_kind(did) {
if let DefKind::TyAlias = tcx.def_kind(did)
&& tcx.type_alias_is_lazy(did)
{
// Type aliases defined in crates that have the
// feature `lazy_type_alias` enabled get encoded as a type alias that normalization will
// then actually instantiate the where bounds of.
let alias_ty = tcx.mk_alias_ty(did, args);
Ty::new_alias(tcx, ty::Weak, alias_ty)
} else {
let ty = tcx.at(span).type_of(did);
if ty.skip_binder().has_opaque_types() {
// Type aliases referring to types that contain opaque types (but aren't just directly
// referencing a single opaque type) get encoded as a type alias that normalization will
// then actually instantiate the where bounds of.
let alias_ty = tcx.mk_alias_ty(did, args);
Ty::new_alias(tcx, ty::Weak, alias_ty)
} else {
ty.instantiate(tcx, args)
}
tcx.at(span).type_of(did).instantiate(tcx, args)
}
}
@ -2164,7 +2157,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
Res::Def(
DefKind::Enum
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::Struct
| DefKind::Union
| DefKind::ForeignTy,
@ -2781,7 +2774,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) {
for br in referenced_regions.difference(&constrained_regions) {
let br_name = match *br {
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) | ty::BrEnv => {
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon | ty::BrEnv => {
"an anonymous lifetime".to_string()
}
ty::BrNamed(_, name) => format!("lifetime `{name}`"),
@ -2789,7 +2782,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut err = generate_err(&br_name);
if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) = *br {
if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon = *br {
// The only way for an anonymous lifetime to wind up
// in the return type but **also** be unconstrained is
// if it only appears in "associated types" in the

View file

@ -640,7 +640,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
check_opaque(tcx, id);
}
}
DefKind::TyAlias { .. } => {
DefKind::TyAlias => {
let pty_ty = tcx.type_of(id.owner_id).instantiate_identity();
let generics = tcx.generics_of(id.owner_id);
check_type_params_are_used(tcx, &generics, pty_ty);

View file

@ -14,6 +14,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::util::ExplicitSelf;
use rustc_middle::ty::{
self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
@ -661,8 +662,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
let impl_trait_ref =
tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().instantiate_identity();
let param_env = tcx.param_env(impl_m_def_id);
// First, check a few of the same things as `compare_impl_method`,
// just so we don't ICE during substitution later.
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
@ -688,13 +687,26 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
let trait_to_placeholder_args =
impl_to_placeholder_args.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_args);
let hybrid_preds = tcx
.predicates_of(impl_m.container_id(tcx))
.instantiate_identity(tcx)
.into_iter()
.chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_placeholder_args))
.map(|(clause, _)| clause);
let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing);
let param_env = traits::normalize_param_env_or_error(
tcx,
param_env,
ObligationCause::misc(tcx.def_span(impl_m_def_id), impl_m_def_id),
);
let infcx = &tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(infcx);
// Normalize the impl signature with fresh variables for lifetime inference.
let norm_cause = ObligationCause::misc(return_span, impl_m_def_id);
let misc_cause = ObligationCause::misc(return_span, impl_m_def_id);
let impl_sig = ocx.normalize(
&norm_cause,
&misc_cause,
param_env,
tcx.liberate_late_bound_regions(
impl_m.def_id,
@ -725,12 +737,68 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
);
}
let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
let trait_sig = ocx.normalize(&misc_cause, param_env, unnormalized_trait_sig);
trait_sig.error_reported()?;
let trait_return_ty = trait_sig.output();
// RPITITs are allowed to use the implied predicates of the method that
// defines them. This is because we want code like:
// ```
// trait Foo {
// fn test<'a, T>(_: &'a T) -> impl Sized;
// }
// impl Foo for () {
// fn test<'a, T>(x: &'a T) -> &'a T { x }
// }
// ```
// .. to compile. However, since we use both the normalized and unnormalized
// inputs and outputs from the substituted trait signature, we will end up
// seeing the hidden type of an RPIT in the signature itself. Naively, this
// means that we will use the hidden type to imply the hidden type's own
// well-formedness.
//
// To avoid this, we replace the infer vars used for hidden type inference
// with placeholders, which imply nothing about outlives bounds, and then
// prove below that the hidden types are well formed.
let universe = infcx.create_next_universe();
let mut idx = 0;
let mapping: FxHashMap<_, _> = collector
.types
.iter()
.map(|(_, &(ty, _))| {
assert!(
infcx.resolve_vars_if_possible(ty) == ty && ty.is_ty_var(),
"{ty:?} should not have been constrained via normalization",
ty = infcx.resolve_vars_if_possible(ty)
);
idx += 1;
(
ty,
Ty::new_placeholder(
tcx,
ty::Placeholder {
universe,
bound: ty::BoundTy {
var: ty::BoundVar::from_usize(idx),
kind: ty::BoundTyKind::Anon,
},
},
),
)
})
.collect();
let mut type_mapper = BottomUpFolder {
tcx,
ty_op: |ty| *mapping.get(&ty).unwrap_or(&ty),
lt_op: |lt| lt,
ct_op: |ct| ct,
};
let wf_tys = FxIndexSet::from_iter(
unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
unnormalized_trait_sig
.inputs_and_output
.iter()
.chain(trait_sig.inputs_and_output.iter())
.map(|ty| ty.fold_with(&mut type_mapper)),
);
match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) {
@ -787,6 +855,20 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
}
}
// FIXME: This has the same issue as #108544, but since this isn't breaking
// existing code, I'm not particularly inclined to do the same hack as above
// where we process wf obligations manually. This can be fixed in a forward-
// compatible way later.
let collected_types = collector.types;
for (_, &(ty, _)) in &collected_types {
ocx.register_obligation(traits::Obligation::new(
tcx,
misc_cause.clone(),
param_env,
ty::ClauseKind::WellFormed(ty.into()),
));
}
// Check that all obligations are satisfied by the implementation's
// RPITs.
let errors = ocx.select_all_or_error();
@ -795,8 +877,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
return Err(reported);
}
let collected_types = collector.types;
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
let outlives_env = OutlivesEnvironment::with_bounds(

View file

@ -5,7 +5,7 @@ use rustc_infer::infer::{outlives::env::OutlivesEnvironment, TyCtxtInferExt};
use rustc_lint_defs::builtin::REFINING_IMPL_TRAIT;
use rustc_middle::traits::{ObligationCause, Reveal};
use rustc_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor,
};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits::{
@ -176,9 +176,13 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
return;
};
// For quicker lookup, use an `IndexSet`
// (we don't use one earlier because it's not foldable..)
let trait_bounds = FxIndexSet::from_iter(trait_bounds);
// For quicker lookup, use an `IndexSet` (we don't use one earlier because
// it's not foldable..).
// Also, We have to anonymize binders in these types because they may contain
// `BrNamed` bound vars, which contain unique `DefId`s which correspond to syntax
// locations that we don't care about when checking bound equality.
let trait_bounds = FxIndexSet::from_iter(trait_bounds.fold_with(&mut Anonymize { tcx }));
let impl_bounds = impl_bounds.fold_with(&mut Anonymize { tcx });
// Find any clauses that are present in the impl's RPITITs that are not
// present in the trait's RPITITs. This will trigger on trivial predicates,
@ -309,3 +313,20 @@ fn type_visibility<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<ty::Visibili
_ => None,
}
}
struct Anonymize<'tcx> {
tcx: TyCtxt<'tcx>,
}
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
self.tcx.anonymize_bound_vars(t)
}
}

View file

@ -137,7 +137,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let name_str = intrinsic_name.as_str();
let bound_vars = tcx.mk_bound_variable_kinds(&[
ty::BoundVariableKind::Region(ty::BrAnon(None)),
ty::BoundVariableKind::Region(ty::BrAnon),
ty::BoundVariableKind::Region(ty::BrEnv),
]);
let mk_va_list_ty = |mutbl| {
@ -145,7 +145,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let region = ty::Region::new_late_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) },
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon },
);
let env_region = ty::Region::new_late_bound(
tcx,
@ -405,7 +405,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
);
let discriminant_def_id = assoc_items[0];
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) };
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon };
(
1,
vec![Ty::new_imm_ref(
@ -463,7 +463,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
}
sym::raw_eq => {
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) };
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon };
let param_ty = Ty::new_imm_ref(
tcx,
ty::Region::new_late_bound(tcx, ty::INNERMOST, br),

View file

@ -246,9 +246,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
// `ForeignItem`s are handled separately.
hir::ItemKind::ForeignMod { .. } => {}
hir::ItemKind::TyAlias(hir_ty, ast_generics) => {
if tcx.features().lazy_type_alias
|| tcx.type_of(item.owner_id).skip_binder().has_opaque_types()
{
if tcx.type_alias_is_lazy(item.owner_id) {
// Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
// E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
@ -1711,10 +1709,8 @@ fn check_variances_for_type_defn<'tcx>(
}
}
ItemKind::TyAlias(..) => {
let ty = tcx.type_of(item.owner_id).instantiate_identity();
if tcx.features().lazy_type_alias || ty.has_opaque_types() {
if ty.references_error() {
if tcx.type_alias_is_lazy(item.owner_id) {
if tcx.type_of(item.owner_id).skip_binder().references_error() {
return;
}
} else {

View file

@ -58,6 +58,7 @@ pub fn provide(providers: &mut Providers) {
*providers = Providers {
type_of: type_of::type_of,
type_of_opaque: type_of::type_of_opaque,
type_alias_is_lazy: type_of::type_alias_is_lazy,
item_bounds: item_bounds::item_bounds,
explicit_item_bounds: item_bounds::explicit_item_bounds,
generics_of: generics_of::generics_of,

View file

@ -856,22 +856,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| {
walk_list!(this, visit_generic_param, generics.params);
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { default, .. } => {
if let Some(ty) = default {
this.visit_ty(ty);
}
}
GenericParamKind::Const { ty, default } => {
this.visit_ty(ty);
if let Some(default) = default {
this.visit_body(this.tcx.hir().body(default.body));
}
}
}
}
walk_list!(this, visit_where_predicate, generics.predicates);
})
}
@ -1000,6 +984,21 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
// like implicit `?Sized` or const-param-has-ty predicates.
}
}
match p.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { default, .. } => {
if let Some(ty) = default {
self.visit_ty(ty);
}
}
GenericParamKind::Const { ty, default } => {
self.visit_ty(ty);
if let Some(default) = default {
self.visit_body(self.tcx.hir().body(default.body));
}
}
}
}
}
@ -1520,7 +1519,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
DefKind::Struct
| DefKind::Union
| DefKind::Enum
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::Trait,
def_id,
) if depth == 0 => Some(def_id),
@ -2030,7 +2029,7 @@ fn is_late_bound_map(
hir::TyKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: Res::Def(DefKind::TyAlias { .. }, alias_def), segments, span },
hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span },
)) => {
// See comments on `ConstrainedCollectorPostAstConv` for why this arm does not just consider
// args to be unconstrained.

View file

@ -623,3 +623,25 @@ fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
.emit();
}
}
pub fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
use hir::intravisit::Visitor;
if tcx.features().lazy_type_alias {
return true;
}
struct HasTait {
has_type_alias_impl_trait: bool,
}
impl<'tcx> Visitor<'tcx> for HasTait {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
if let hir::TyKind::OpaqueDef(..) = t.kind {
self.has_type_alias_impl_trait = true;
} else {
hir::intravisit::walk_ty(self, t);
}
}
}
let mut has_tait = HasTait { has_type_alias_impl_trait: false };
has_tait.visit_ty(tcx.hir().expect_item(def_id).expect_ty_alias().0);
has_tait.has_type_alias_impl_trait
}

View file

@ -6,7 +6,7 @@
use hir::def_id::{DefId, LocalDefId};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
use super::terms::VarianceTerm::*;
@ -78,9 +78,7 @@ pub fn add_constraints_from_crate<'a, 'tcx>(
}
}
DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id),
DefKind::TyAlias { lazy }
if lazy || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
{
DefKind::TyAlias if tcx.type_alias_is_lazy(def_id) => {
constraint_cx.build_constraints_for_item(def_id)
}
_ => {}
@ -110,8 +108,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
// The type as returned by `type_of` is the underlying type and generally not a weak projection.
// Therefore we need to check the `DefKind` first.
if let DefKind::TyAlias { lazy } = tcx.def_kind(def_id)
&& (lazy || ty.has_opaque_types())
if let DefKind::TyAlias = tcx.def_kind(def_id)
&& tcx.type_alias_is_lazy(def_id)
{
self.add_constraints_from_ty(current_item, ty, self.covariant);
return;

View file

@ -8,7 +8,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, CrateVariancesMap, GenericArgsRef, Ty, TyCtxt};
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
use std::ops::ControlFlow;
/// Defines the `TermsContext` basically houses an arena where we can
@ -56,9 +56,7 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
let crate_map = tcx.crate_variances(());
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
}
DefKind::TyAlias { lazy }
if lazy || tcx.type_of(item_def_id).instantiate_identity().has_opaque_types() =>
{
DefKind::TyAlias if tcx.type_alias_is_lazy(item_def_id) => {
// These are inferred.
let crate_map = tcx.crate_variances(());
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);

View file

@ -12,7 +12,7 @@
use rustc_arena::DroplessArena;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{self, TyCtxt};
use std::fmt;
use self::VarianceTerm::*;
@ -97,9 +97,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
}
}
DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id),
DefKind::TyAlias { lazy }
if lazy || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
{
DefKind::TyAlias if tcx.type_alias_is_lazy(def_id) => {
terms_cx.add_inferreds_for_item(def_id)
}
_ => {}

View file

@ -204,7 +204,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>
&[ty::GenericArg::from(ty::Region::new_late_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon(None) },
ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon },
))],
);
let panic_info_ref_ty = Ty::new_imm_ref(
@ -212,14 +212,14 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>
ty::Region::new_late_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) },
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon },
),
panic_info_ty,
);
let bounds = tcx.mk_bound_variable_kinds(&[
ty::BoundVariableKind::Region(ty::BrAnon(None)),
ty::BoundVariableKind::Region(ty::BrAnon(None)),
ty::BoundVariableKind::Region(ty::BrAnon),
ty::BoundVariableKind::Region(ty::BrAnon),
]);
let expected_sig = ty::Binder::bind_with_vars(
tcx.mk_fn_sig([panic_info_ref_ty], tcx.types.never, false, fn_sig.unsafety, Abi::Rust),

View file

@ -530,7 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// When encountering a type error on the value of a `break`, try to point at the reason for the
// expected type.
fn annotate_loop_expected_due_to_inference(
pub fn annotate_loop_expected_due_to_inference(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
@ -540,16 +540,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
};
let mut parent_id = self.tcx.hir().parent_id(expr.hir_id);
loop {
let mut parent;
'outer: loop {
// Climb the HIR tree to see if the current `Expr` is part of a `break;` statement.
let Some(hir::Node::Expr(parent)) = self.tcx.hir().find(parent_id) else {
let Some(
hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Semi(&ref p), .. })
| hir::Node::Block(hir::Block { expr: Some(&ref p), .. })
| hir::Node::Expr(&ref p),
) = self.tcx.hir().find(parent_id)
else {
break;
};
parent_id = self.tcx.hir().parent_id(parent.hir_id);
parent = p;
parent_id = self.tcx.hir().parent_id(parent_id);
let hir::ExprKind::Break(destination, _) = parent.kind else {
continue;
};
let mut parent_id = parent.hir_id;
let mut parent_id = parent_id;
let mut direct = false;
loop {
// Climb the HIR tree to find the (desugared) `loop` this `break` corresponds to.
let parent = match self.tcx.hir().find(parent_id) {
@ -565,14 +573,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
parent_id = self.tcx.hir().parent_id(*hir_id);
parent
}
Some(hir::Node::Block(hir::Block { .. })) => {
Some(hir::Node::Block(_)) => {
parent_id = self.tcx.hir().parent_id(parent_id);
parent
}
_ => break,
};
if let hir::ExprKind::Loop(_, label, _, span) = parent.kind
&& destination.label == label
if let hir::ExprKind::Loop(..) = parent.kind {
// When you have `'a: loop { break; }`, the `break` corresponds to the labeled
// loop, so we need to account for that.
direct = !direct;
}
if let hir::ExprKind::Loop(block, label, _, span) = parent.kind
&& (destination.label == label || direct)
{
if let Some((reason_span, message)) =
self.maybe_get_coercion_reason(parent_id, parent.span)
@ -582,8 +595,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
format!("this loop is expected to be of type `{expected}`"),
);
break 'outer;
} else {
// Locate all other `break` statements within the same `loop` that might
// have affected inference.
struct FindBreaks<'tcx> {
label: Option<rustc_ast::Label>,
uses: Vec<&'tcx hir::Expr<'tcx>>,
nest_depth: usize,
}
impl<'tcx> Visitor<'tcx> for FindBreaks<'tcx> {
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
let nest_depth = self.nest_depth;
if let hir::ExprKind::Loop(_, label, _, _) = ex.kind {
if label == self.label {
// Account for `'a: loop { 'a: loop {...} }`.
return;
}
self.nest_depth += 1;
}
if let hir::ExprKind::Break(destination, _) = ex.kind
&& (self.label == destination.label
// Account for `loop { 'a: loop { loop { break; } } }`.
|| destination.label.is_none() && self.nest_depth == 0)
{
self.uses.push(ex);
}
hir::intravisit::walk_expr(self, ex);
self.nest_depth = nest_depth;
}
}
let mut expr_finder = FindBreaks { label, uses: vec![], nest_depth: 0 };
expr_finder.visit_block(block);
let mut exit = false;
for ex in expr_finder.uses {
let hir::ExprKind::Break(_, val) = ex.kind else {
continue;
};
let ty = match val {
Some(val) => {
match self.typeck_results.borrow().expr_ty_adjusted_opt(val) {
None => continue,
Some(ty) => ty,
}
}
None => self.tcx.types.unit,
};
if self.can_eq(self.param_env, ty, expected) {
err.span_label(
ex.span,
format!("expected because of this `break`"),
);
exit = true;
}
}
if exit {
break 'outer;
}
}
break;
}
}
}

View file

@ -43,7 +43,10 @@ use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
use rustc_middle::ty::error::TypeError::FieldMisMatch;
use rustc_middle::ty::error::{
ExpectedFound,
TypeError::{FieldMisMatch, Sorts},
};
use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt};
use rustc_session::errors::ExprParenthesesNeeded;
@ -664,15 +667,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.suggest_mismatched_types_on_tail(
&mut err, expr, ty, e_ty, target_id,
);
let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty }));
self.annotate_loop_expected_due_to_inference(&mut err, expr, error);
if let Some(val) = ty_kind_suggestion(ty) {
let label = destination
.label
.map(|l| format!(" {}", l.ident))
.unwrap_or_else(String::new);
err.span_suggestion(
expr.span,
err.span_suggestion_verbose(
expr.span.shrink_to_hi(),
"give it a value of the expected type",
format!("break{label} {val}"),
format!(" {val}"),
Applicability::HasPlaceholders,
);
}
@ -717,7 +718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// ... except when we try to 'break rust;'.
// ICE this expression in particular (see #43162).
if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind {
if path.segments.len() == 1 && path.segments[0].ident.name == sym::rust {
if let [segment] = path.segments && segment.ident.name == sym::rust {
fatally_break_rust(self.tcx);
}
}

View file

@ -1370,10 +1370,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
_ => bug!("unexpected type: {:?}", ty.normalized),
},
Res::Def(
DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy,
_,
)
Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
| Res::SelfTyParam { .. }
| Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() {
Some(adt) if !adt.is_enum() => {

View file

@ -65,6 +65,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expr = expr.peel_drop_temps();
self.suggest_missing_semicolon(err, expr, expected, false);
let mut pointing_at_return_type = false;
if let hir::ExprKind::Break(..) = expr.kind {
// `break` type mismatches provide better context for tail `loop` expressions.
return false;
}
if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
pointing_at_return_type = self.suggest_missing_return_type(
err,

View file

@ -464,7 +464,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
// Opaque types can't have field projections, but we can instead convert
// the current place in-place (heh) to the hidden type, and then apply all
// follow up projections on that.
if node_ty != place_ty && place_ty.has_opaque_types() {
if node_ty != place_ty && matches!(place_ty.kind(), ty::Alias(ty::Opaque, ..)) {
projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
}
projections.push(Projection { kind, ty });
@ -557,10 +557,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id))
}
Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
| Res::Def(
DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy,
_,
)
| Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
| Res::SelfCtor(..)
| Res::SelfTyParam { .. }
| Res::SelfTyAlias { .. } => {

View file

@ -28,8 +28,8 @@ pub use persist::load_query_result_cache;
pub use persist::prepare_session_directory;
pub use persist::save_dep_graph;
pub use persist::save_work_product_index;
pub use persist::setup_dep_graph;
pub use persist::LoadResult;
pub use persist::{build_dep_graph, load_dep_graph, DepGraphFuture};
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_fluent_macro::fluent_messages;

View file

@ -3,17 +3,19 @@
use crate::errors;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::unord::UnordMap;
use rustc_middle::dep_graph::{DepsType, SerializedDepGraph, WorkProductMap};
use rustc_middle::dep_graph::{DepGraph, DepsType, SerializedDepGraph, WorkProductMap};
use rustc_middle::query::on_disk_cache::OnDiskCache;
use rustc_serialize::opaque::MemDecoder;
use rustc_serialize::Decodable;
use rustc_session::config::IncrementalStateAssertion;
use rustc_session::Session;
use rustc_session::{Session, StableCrateId};
use rustc_span::{ErrorGuaranteed, Symbol};
use std::path::{Path, PathBuf};
use super::data::*;
use super::file_format;
use super::fs::*;
use super::save::build_dep_graph;
use super::work_product;
#[derive(Debug)]
@ -72,21 +74,12 @@ impl<T: Default> LoadResult<T> {
}
fn load_data(path: &Path, sess: &Session) -> LoadResult<(Mmap, usize)> {
load_data_no_sess(
match file_format::read_file(
path,
sess.opts.unstable_opts.incremental_info,
sess.is_nightly_build(),
sess.cfg_version,
)
}
fn load_data_no_sess(
path: &Path,
report_incremental_info: bool,
is_nightly_build: bool,
cfg_version: &'static str,
) -> LoadResult<(Mmap, usize)> {
match file_format::read_file(path, report_incremental_info, is_nightly_build, cfg_version) {
) {
Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos },
Ok(None) => {
// The file either didn't exist or was produced by an incompatible
@ -102,39 +95,12 @@ fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) {
work_product::delete_workproduct_files(sess, &swp.work_product);
}
/// Either a result that has already be computed or a
/// handle that will let us wait until it is computed
/// by a background thread.
pub enum MaybeAsync<T> {
Sync(T),
Async(std::thread::JoinHandle<T>),
}
impl<T> MaybeAsync<LoadResult<T>> {
/// Accesses the data returned in [`LoadResult::Ok`] in an asynchronous way if possible.
pub fn open(self) -> LoadResult<T> {
match self {
MaybeAsync::Sync(result) => result,
MaybeAsync::Async(handle) => {
handle.join().unwrap_or_else(|e| LoadResult::DecodeIncrCache(e))
}
}
}
}
/// An asynchronous type for computing the dependency graph.
pub type DepGraphFuture = MaybeAsync<LoadResult<(SerializedDepGraph, WorkProductMap)>>;
/// Launch a thread and load the dependency graph in the background.
pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
// Since `sess` isn't `Sync`, we perform all accesses to `sess`
// before we fire the background thread.
fn load_dep_graph(sess: &Session) -> LoadResult<(SerializedDepGraph, WorkProductMap)> {
let prof = sess.prof.clone();
if sess.opts.incremental.is_none() {
// No incremental compilation.
return MaybeAsync::Sync(LoadResult::Ok { data: Default::default() });
return LoadResult::Ok { data: Default::default() };
}
let _timer = sess.prof.generic_activity("incr_comp_prepare_load_dep_graph");
@ -142,7 +108,6 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
// Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`.
// Fortunately, we just checked that this isn't the case.
let path = dep_graph_path(&sess);
let report_incremental_info = sess.opts.unstable_opts.incremental_info;
let expected_hash = sess.opts.dep_tracking_hash(false);
let mut prev_work_products = UnordMap::default();
@ -180,40 +145,35 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
}
}
let is_nightly_build = sess.is_nightly_build();
let cfg_version = sess.cfg_version;
let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
MaybeAsync::Async(std::thread::spawn(move || {
let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
match load_data(&path, sess) {
LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err),
LoadResult::DecodeIncrCache(err) => LoadResult::DecodeIncrCache(err),
LoadResult::Ok { data: (bytes, start_pos) } => {
let mut decoder = MemDecoder::new(&bytes, start_pos);
let prev_commandline_args_hash = u64::decode(&mut decoder);
match load_data_no_sess(&path, report_incremental_info, is_nightly_build, cfg_version) {
LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err),
LoadResult::DecodeIncrCache(err) => LoadResult::DecodeIncrCache(err),
LoadResult::Ok { data: (bytes, start_pos) } => {
let mut decoder = MemDecoder::new(&bytes, start_pos);
let prev_commandline_args_hash = u64::decode(&mut decoder);
if prev_commandline_args_hash != expected_hash {
if report_incremental_info {
eprintln!(
"[incremental] completely ignoring cache because of \
if prev_commandline_args_hash != expected_hash {
if sess.opts.unstable_opts.incremental_info {
eprintln!(
"[incremental] completely ignoring cache because of \
differing commandline arguments"
);
}
// We can't reuse the cache, purge it.
debug!("load_dep_graph_new: differing commandline arg hashes");
// No need to do any further work
return LoadResult::DataOutOfDate;
);
}
// We can't reuse the cache, purge it.
debug!("load_dep_graph_new: differing commandline arg hashes");
let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder);
LoadResult::Ok { data: (dep_graph, prev_work_products) }
// No need to do any further work
return LoadResult::DataOutOfDate;
}
let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder);
LoadResult::Ok { data: (dep_graph, prev_work_products) }
}
}))
}
}
/// Attempts to load the query result cache from disk
@ -235,3 +195,35 @@ pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> {
_ => Some(OnDiskCache::new_empty(sess.source_map())),
}
}
/// Setups the dependency graph by loading an existing graph from disk and set up streaming of a
/// new graph to an incremental session directory.
pub fn setup_dep_graph(
sess: &Session,
crate_name: Symbol,
stable_crate_id: StableCrateId,
) -> Result<DepGraph, ErrorGuaranteed> {
// `load_dep_graph` can only be called after `prepare_session_directory`.
prepare_session_directory(sess, crate_name, stable_crate_id)?;
let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess));
if sess.opts.incremental.is_some() {
sess.time("incr_comp_garbage_collect_session_directories", || {
if let Err(e) = garbage_collect_session_directories(sess) {
warn!(
"Error while trying to garbage collect incremental \
compilation cache directory: {}",
e
);
}
});
}
Ok(res
.and_then(|result| {
let (prev_graph, prev_work_products) = result.open(sess);
build_dep_graph(sess, prev_graph, prev_work_products)
})
.unwrap_or_else(DepGraph::new_disabled))
}

View file

@ -16,9 +16,8 @@ pub use fs::in_incr_comp_dir;
pub use fs::in_incr_comp_dir_sess;
pub use fs::prepare_session_directory;
pub use load::load_query_result_cache;
pub use load::setup_dep_graph;
pub use load::LoadResult;
pub use load::{load_dep_graph, DepGraphFuture};
pub use save::build_dep_graph;
pub use save::save_dep_graph;
pub use save::save_work_product_index;
pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir;

View file

@ -147,7 +147,7 @@ fn encode_query_cache(tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult
/// execution, the new dependency information is not kept in memory but directly
/// output to this file. `save_dep_graph` then finalizes the staging dep-graph
/// and moves it to the permanent dep-graph path
pub fn build_dep_graph(
pub(crate) fn build_dep_graph(
sess: &Session,
prev_graph: SerializedDepGraph,
prev_work_products: WorkProductMap,

View file

@ -56,11 +56,8 @@ impl<'a> DescriptionCtx<'a> {
(Some(span), "as_defined", name.to_string())
}
}
ty::BrAnon(span) => {
let span = match span {
Some(_) => span,
None => Some(tcx.def_span(scope)),
};
ty::BrAnon => {
let span = Some(tcx.def_span(scope));
(span, "defined_here", String::new())
}
_ => {

View file

@ -775,7 +775,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
let var = self.canonical_var(info, r.into());
let br = ty::BoundRegion { var, kind: ty::BrAnon(None) };
let br = ty::BoundRegion { var, kind: ty::BrAnon };
ty::Region::new_late_bound(self.interner(), self.binder_index, br)
}

View file

@ -242,12 +242,9 @@ fn msg_span_from_named_region<'tcx>(
};
(text, Some(span))
}
ty::BrAnon(span) => (
ty::BrAnon => (
"the anonymous lifetime as defined here".to_string(),
Some(match span {
Some(span) => span,
None => tcx.def_span(scope)
})
Some(tcx.def_span(scope))
),
_ => (
format!("the lifetime `{region}` as defined here"),
@ -262,11 +259,7 @@ fn msg_span_from_named_region<'tcx>(
..
}) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))),
ty::RePlaceholder(ty::PlaceholderRegion {
bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon(Some(span)), .. },
..
}) => ("the anonymous lifetime defined here".to_owned(), Some(span)),
ty::RePlaceholder(ty::PlaceholderRegion {
bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon(None), .. },
bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon, .. },
..
}) => ("an anonymous lifetime".to_owned(), None),
_ => bug!("{:?}", region),

View file

@ -918,7 +918,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
//
// See the `need_type_info/issue-103053.rs` test for
// a example.
if !matches!(path.res, Res::Def(DefKind::TyAlias { .. }, _)) => {
if !matches!(path.res, Res::Def(DefKind::TyAlias, _)) => {
if let Some(ty) = self.opt_node_type(expr.hir_id)
&& let ty::Adt(_, args) = ty.kind()
{
@ -1047,7 +1047,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
) => {
if tcx.res_generics_def_id(path.res) != Some(def.did()) {
match path.res {
Res::Def(DefKind::TyAlias { .. }, _) => {
Res::Def(DefKind::TyAlias, _) => {
// FIXME: Ideally we should support this. For that
// we have to map back from the self type to the
// type alias though. That's difficult.

View file

@ -61,7 +61,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let is_impl_item = region_info.is_impl_item;
match br {
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) => {}
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon => {}
_ => {
/* not an anonymous region */
debug!("try_report_named_anon_conflict: not an anonymous region");

View file

@ -36,15 +36,13 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
ty::BrNamed(def_id, symbol) => {
(Some(self.tcx().def_span(def_id)), Some(symbol))
}
ty::BrAnon(span) => (*span, None),
ty::BrEnv => (None, None),
ty::BrAnon | ty::BrEnv => (None, None),
};
let (sup_span, sup_symbol) = match sup_name {
ty::BrNamed(def_id, symbol) => {
(Some(self.tcx().def_span(def_id)), Some(symbol))
}
ty::BrAnon(span) => (*span, None),
ty::BrEnv => (None, None),
ty::BrAnon | ty::BrEnv => (None, None),
};
let diag = match (sub_span, sup_span, sub_symbol, sup_symbol) {
(Some(sub_span), Some(sup_span), Some(&sub_symbol), Some(&sup_symbol)) => {

View file

@ -10,7 +10,7 @@ use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, Lrc, OnceLock, WorkerLocal};
use rustc_hir::def_id::{StableCrateId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
use rustc_incremental::DepGraphFuture;
use rustc_incremental::setup_dep_graph;
use rustc_metadata::creader::CStore;
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
@ -19,7 +19,6 @@ use rustc_session::config::{self, CrateType, OutputFilenames, OutputType};
use rustc_session::cstore::Untracked;
use rustc_session::{output::find_crate_name, Session};
use rustc_span::symbol::sym;
use rustc_span::Symbol;
use std::any::Any;
use std::cell::{RefCell, RefMut};
use std::sync::Arc;
@ -132,43 +131,6 @@ impl<'tcx> Queries<'tcx> {
})
}
fn dep_graph_future(
&self,
crate_name: Symbol,
stable_crate_id: StableCrateId,
) -> Result<Option<DepGraphFuture>> {
let sess = self.session();
// `load_dep_graph` can only be called after `prepare_session_directory`.
rustc_incremental::prepare_session_directory(sess, crate_name, stable_crate_id)?;
let res = sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess));
if sess.opts.incremental.is_some() {
sess.time("incr_comp_garbage_collect_session_directories", || {
if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
warn!(
"Error while trying to garbage collect incremental \
compilation cache directory: {}",
e
);
}
});
}
Ok(res)
}
fn dep_graph(&self, dep_graph_future: Option<DepGraphFuture>) -> DepGraph {
dep_graph_future
.and_then(|future| {
let sess = self.session();
let (prev_graph, prev_work_products) =
sess.time("blocked_on_dep_graph_loading", || future.open().open(sess));
rustc_incremental::build_dep_graph(sess, prev_graph, prev_work_products)
})
.unwrap_or_else(DepGraph::new_disabled)
}
pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
self.gcx.compute(|| {
let sess = self.session();
@ -184,10 +146,7 @@ impl<'tcx> Queries<'tcx> {
sess.opts.cg.metadata.clone(),
sess.cfg_version,
);
// Compute the dependency graph (in the background). We want to do this as early as
// possible, to give the DepGraph maximum time to load before `dep_graph` is called.
let dep_graph_future = self.dep_graph_future(crate_name, stable_crate_id)?;
let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id)?;
let lint_store = Lrc::new(passes::create_lint_store(
sess,
@ -210,7 +169,7 @@ impl<'tcx> Queries<'tcx> {
crate_types,
stable_crate_id,
lint_store,
self.dep_graph(dep_graph_future),
dep_graph,
untracked,
&self.gcx_cell,
&self.arena,

View file

@ -1454,13 +1454,13 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
let hir::ItemKind::TyAlias(hir_ty, type_alias_generics) = &item.kind else { return };
if cx.tcx.features().lazy_type_alias {
// Bounds of lazy type aliases are respected.
// Bounds of lazy type aliases and TAITs are respected.
if cx.tcx.type_alias_is_lazy(item.owner_id) {
return;
}
let ty = cx.tcx.type_of(item.owner_id).skip_binder();
if ty.has_opaque_types() || ty.has_inherent_projections() {
if ty.has_inherent_projections() {
// Bounds of type aliases that contain opaque types or inherent projections are respected.
// E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`, `type X = Type::Inherent;`.
return;

View file

@ -2311,6 +2311,57 @@ declare_lint! {
};
}
declare_lint! {
/// The `const_patterns_without_partial_eq` lint detects constants that are used in patterns,
/// whose type does not implement `PartialEq`.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(const_patterns_without_partial_eq)]
///
/// trait EnumSetType {
/// type Repr;
/// }
///
/// enum Enum8 { }
/// impl EnumSetType for Enum8 {
/// type Repr = u8;
/// }
///
/// #[derive(PartialEq, Eq)]
/// struct EnumSet<T: EnumSetType> {
/// __enumset_underlying: T::Repr,
/// }
///
/// const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
///
/// fn main() {
/// match CONST_SET {
/// CONST_SET => { /* ok */ }
/// _ => panic!("match fell through?"),
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Previous versions of Rust accepted constants in patterns, even if those constants' types
/// did not have `PartialEq` implemented. The compiler falls back to comparing the value
/// field-by-field. In the future we'd like to ensure that pattern matching always
/// follows `PartialEq` semantics, so that trait bound will become a requirement for
/// matching on constants.
pub CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
Warn,
"constant in pattern does not implement `PartialEq`",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
reference: "issue #116122 <https://github.com/rust-lang/rust/issues/116122>",
};
}
declare_lint! {
/// The `ambiguous_associated_items` lint detects ambiguity between
/// [associated items] and [enum variants].
@ -3357,6 +3408,7 @@ declare_lint_pass! {
CONFLICTING_REPR_HINTS,
CONST_EVALUATABLE_UNCHECKED,
CONST_ITEM_MUTATION,
CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
DEAD_CODE,
DEPRECATED,
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,

View file

@ -416,6 +416,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
bool RelaxELFRelocations,
bool UseInitArray,
const char *SplitDwarfFile,
const char *OutputObjFile,
const char *DebugInfoCompression,
bool ForceEmulatedTls,
const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) {
@ -448,6 +449,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
if (SplitDwarfFile) {
Options.MCOptions.SplitDwarfFile = SplitDwarfFile;
}
if (OutputObjFile) {
Options.ObjectFilenameForDebug = OutputObjFile;
}
#if LLVM_VERSION_GE(16, 0)
if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) {
Options.CompressDebugSections = DebugCompressionType::Zlib;

View file

@ -210,6 +210,7 @@ provide! { tcx, def_id, other, cdata,
inferred_outlives_of => { table_defaulted_array }
super_predicates_of => { table }
type_of => { table }
type_alias_is_lazy => { cdata.root.tables.type_alias_is_lazy.get(cdata, def_id.index) }
variances_of => { table }
fn_sig => { table }
codegen_fn_attrs => { table }

View file

@ -31,7 +31,6 @@ use rustc_middle::query::Providers;
use rustc_middle::traits::specialization_graph;
use rustc_middle::ty::codec::TyEncoder;
use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, AssocItemContainer, SymbolName, Ty, TyCtxt};
use rustc_middle::util::common::to_readable_str;
use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
@ -827,7 +826,7 @@ fn should_encode_span(def_kind: DefKind) -> bool {
| DefKind::Enum
| DefKind::Variant
| DefKind::Trait
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
@ -862,7 +861,7 @@ fn should_encode_attrs(def_kind: DefKind) -> bool {
| DefKind::Enum
| DefKind::Variant
| DefKind::Trait
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
@ -903,7 +902,7 @@ fn should_encode_expn_that_defined(def_kind: DefKind) -> bool {
| DefKind::Variant
| DefKind::Trait
| DefKind::Impl { .. } => true,
DefKind::TyAlias { .. }
DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
@ -938,7 +937,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
| DefKind::Enum
| DefKind::Variant
| DefKind::Trait
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
@ -982,7 +981,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
| DefKind::Const
| DefKind::Fn
| DefKind::ForeignMod
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::OpaqueTy
| DefKind::Enum
| DefKind::Union
@ -1092,9 +1091,7 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def
| DefKind::Closure
| DefKind::Generator
| DefKind::ExternCrate => false,
DefKind::TyAlias { lazy } => {
lazy || tcx.type_of(def_id).instantiate_identity().has_opaque_types()
}
DefKind::TyAlias => tcx.type_alias_is_lazy(def_id),
}
}
@ -1105,7 +1102,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
| DefKind::Enum
| DefKind::Variant
| DefKind::Trait
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
@ -1145,7 +1142,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
| DefKind::Fn
| DefKind::Const
| DefKind::Static(..)
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::Impl { .. }
| DefKind::AssocFn
@ -1205,7 +1202,7 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool {
| DefKind::Const
| DefKind::Static(..)
| DefKind::Ctor(..)
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::OpaqueTy
| DefKind::ForeignTy
| DefKind::Impl { .. }
@ -1246,7 +1243,7 @@ fn should_encode_constness(def_kind: DefKind) -> bool {
| DefKind::AssocConst
| DefKind::AnonConst
| DefKind::Static(..)
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::OpaqueTy
| DefKind::Impl { of_trait: false }
| DefKind::ForeignTy
@ -1279,7 +1276,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
| DefKind::Field
| DefKind::Fn
| DefKind::Static(..)
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::OpaqueTy
| DefKind::ForeignTy
| DefKind::Impl { .. }
@ -1451,6 +1448,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
if let DefKind::Macro(_) = def_kind {
self.encode_info_for_macro(local_id);
}
if let DefKind::TyAlias = def_kind {
self.tables
.type_alias_is_lazy
.set(def_id.index, self.tcx.type_alias_is_lazy(def_id));
}
if let DefKind::OpaqueTy = def_kind {
self.encode_explicit_item_bounds(def_id);
self.tables

View file

@ -383,6 +383,7 @@ define_tables! {
is_intrinsic: Table<DefIndex, bool>,
is_macro_rules: Table<DefIndex, bool>,
is_type_alias_impl_trait: Table<DefIndex, bool>,
type_alias_is_lazy: Table<DefIndex, bool>,
attr_flags: Table<DefIndex, AttrFlags>,
def_path_hashes: Table<DefIndex, DefPathHash>,
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,

View file

@ -145,8 +145,7 @@ fixed_size_enum! {
( Enum )
( Variant )
( Trait )
( TyAlias { lazy: false } )
( TyAlias { lazy: true } )
( TyAlias )
( ForeignTy )
( TraitAlias )
( AssocTy )

View file

@ -196,9 +196,7 @@ impl<'hir> Map<'hir> {
ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
ItemKind::Mod(..) => DefKind::Mod,
ItemKind::OpaqueTy(..) => DefKind::OpaqueTy,
ItemKind::TyAlias(..) => {
DefKind::TyAlias { lazy: self.tcx.features().lazy_type_alias }
}
ItemKind::TyAlias(..) => DefKind::TyAlias,
ItemKind::Enum(..) => DefKind::Enum,
ItemKind::Struct(..) => DefKind::Struct,
ItemKind::Union(..) => DefKind::Union,

View file

@ -455,7 +455,7 @@ impl<'tcx> CanonicalVarValues<'tcx> {
CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_usize(i),
kind: ty::BrAnon(None),
kind: ty::BrAnon,
};
ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into()
}

View file

@ -414,8 +414,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
let inner = tcx.fold_regions(ty, |r, depth| match r.kind() {
ty::ReVar(vid) => {
let br =
ty::BoundRegion { var: ty::BoundVar::new(vid.index()), kind: ty::BrAnon(None) };
let br = ty::BoundRegion { var: ty::BoundVar::new(vid.index()), kind: ty::BrAnon };
ty::Region::new_late_bound(tcx, depth, br)
}
_ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),

View file

@ -229,7 +229,7 @@ rustc_queries! {
action = {
use rustc_hir::def::DefKind;
match tcx.def_kind(key) {
DefKind::TyAlias { .. } => "expanding type alias",
DefKind::TyAlias => "expanding type alias",
DefKind::TraitAlias => "expanding trait alias",
_ => "computing type of",
}
@ -251,6 +251,14 @@ rustc_queries! {
}
}
query type_alias_is_lazy(key: DefId) -> bool {
desc { |tcx|
"computing whether `{path}` is a lazy type alias",
path = tcx.def_path_str(key),
}
separate_provide_extern
}
query collect_return_position_impl_trait_in_trait_tys(key: DefId)
-> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed>
{

View file

@ -448,7 +448,7 @@ impl<'tcx> AdtDef<'tcx> {
Res::Def(DefKind::Ctor(..), cid) => self.variant_with_ctor_id(cid),
Res::Def(DefKind::Struct, _)
| Res::Def(DefKind::Union, _)
| Res::Def(DefKind::TyAlias { .. }, _)
| Res::Def(DefKind::TyAlias, _)
| Res::Def(DefKind::AssocTy, _)
| Res::SelfTyParam { .. }
| Res::SelfTyAlias { .. }

View file

@ -318,7 +318,7 @@ pub struct CommonLifetimes<'tcx> {
pub re_vars: Vec<Region<'tcx>>,
/// Pre-interned values of the form:
/// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon(None) })`
/// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon })`
/// for small values of `i` and `v`.
pub re_late_bounds: Vec<Vec<Region<'tcx>>>,
}
@ -395,7 +395,7 @@ impl<'tcx> CommonLifetimes<'tcx> {
.map(|v| {
mk(ty::ReLateBound(
ty::DebruijnIndex::from(i),
ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BrAnon(None) },
ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BrAnon },
))
})
.collect()
@ -1114,7 +1114,7 @@ impl<'tcx> TyCtxt<'tcx> {
if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id)
&& let hir::TyKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: hir::def::Res::Def(DefKind::TyAlias { .. }, def_id), .. }, )) = hir_output.kind
hir::Path { res: hir::def::Res::Def(DefKind::TyAlias, def_id), .. }, )) = hir_output.kind
&& let Some(local_id) = def_id.as_local()
&& let Some(alias_ty) = self.hir().get_by_def_id(local_id).alias_ty() // it is type alias
&& let Some(alias_generics) = self.hir().get_by_def_id(local_id).generics()

View file

@ -493,7 +493,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> {
Alias(Opaque, AliasTy { def_id, .. }) => {
let parent = self.tcx.parent(def_id);
let parent_ty = self.tcx.type_of(parent).instantiate_identity();
if let DefKind::TyAlias { .. } | DefKind::AssocTy = self.tcx.def_kind(parent)
if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent)
&& let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind()
&& parent_opaque_def_id == def_id
{
@ -577,7 +577,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
Alias(Opaque, AliasTy { def_id, .. }) => {
let parent = self.tcx.parent(def_id);
let parent_ty = self.tcx.type_of(parent).instantiate_identity();
if let hir::def::DefKind::TyAlias { .. } | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
&& let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind()
&& parent_opaque_def_id == def_id
{

View file

@ -385,7 +385,7 @@ impl<'tcx> TyCtxt<'tcx> {
let index = entry.index();
let var = ty::BoundVar::from_usize(index);
let kind = entry
.or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(None)))
.or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon))
.expect_region();
let br = ty::BoundRegion { var, kind };
ty::Region::new_late_bound(self.tcx, ty::INNERMOST, br)

View file

@ -118,7 +118,7 @@ impl<'tcx> Instance<'tcx> {
/// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
let ty = tcx.type_of(self.def.def_id());
tcx.subst_and_normalize_erasing_regions(self.args, param_env, ty)
tcx.instantiate_and_normalize_erasing_regions(self.args, param_env, ty)
}
/// Finds a crate that contains a monomorphization of this instance that
@ -580,7 +580,7 @@ impl<'tcx> Instance<'tcx> {
self.def.has_polymorphic_mir_body().then_some(self.args)
}
pub fn subst_mir<T>(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<&T>) -> T
pub fn instantiate_mir<T>(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<&T>) -> T
where
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
{
@ -593,7 +593,7 @@ impl<'tcx> Instance<'tcx> {
}
#[inline(always)]
pub fn subst_mir_and_normalize_erasing_regions<T>(
pub fn instantiate_mir_and_normalize_erasing_regions<T>(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@ -603,14 +603,14 @@ impl<'tcx> Instance<'tcx> {
T: TypeFoldable<TyCtxt<'tcx>> + Clone,
{
if let Some(args) = self.args_for_mir_body() {
tcx.subst_and_normalize_erasing_regions(args, param_env, v)
tcx.instantiate_and_normalize_erasing_regions(args, param_env, v)
} else {
tcx.normalize_erasing_regions(param_env, v.skip_binder())
}
}
#[inline(always)]
pub fn try_subst_mir_and_normalize_erasing_regions<T>(
pub fn try_instantiate_mir_and_normalize_erasing_regions<T>(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@ -620,7 +620,7 @@ impl<'tcx> Instance<'tcx> {
T: TypeFoldable<TyCtxt<'tcx>> + Clone,
{
if let Some(args) = self.args_for_mir_body() {
tcx.try_subst_and_normalize_erasing_regions(args, param_env, v)
tcx.try_instantiate_and_normalize_erasing_regions(args, param_env, v)
} else {
tcx.try_normalize_erasing_regions(param_env, v.skip_binder())
}

View file

@ -134,8 +134,9 @@ impl<'tcx> TyCtxt<'tcx> {
/// in-scope substitutions and then normalizing any associated
/// types.
/// Panics if normalization fails. In case normalization might fail
/// use `try_subst_and_normalize_erasing_regions` instead.
pub fn subst_and_normalize_erasing_regions<T>(
/// use `try_instantiate_and_normalize_erasing_regions` instead.
#[instrument(level = "debug", skip(self))]
pub fn instantiate_and_normalize_erasing_regions<T>(
self,
param_args: GenericArgsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@ -144,22 +145,16 @@ impl<'tcx> TyCtxt<'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
debug!(
"subst_and_normalize_erasing_regions(\
param_args={:?}, \
value={:?}, \
param_env={:?})",
param_args, value, param_env,
);
let substituted = value.instantiate(self, param_args);
self.normalize_erasing_regions(param_env, substituted)
}
/// Monomorphizes a type from the AST by first applying the
/// in-scope substitutions and then trying to normalize any associated
/// types. Contrary to `subst_and_normalize_erasing_regions` this does
/// types. Contrary to `instantiate_and_normalize_erasing_regions` this does
/// not assume that normalization succeeds.
pub fn try_subst_and_normalize_erasing_regions<T>(
#[instrument(level = "debug", skip(self))]
pub fn try_instantiate_and_normalize_erasing_regions<T>(
self,
param_args: GenericArgsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@ -168,13 +163,6 @@ impl<'tcx> TyCtxt<'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
debug!(
"subst_and_normalize_erasing_regions(\
param_args={:?}, \
value={:?}, \
param_env={:?})",
param_args, value, param_env,
);
let substituted = value.instantiate(self, param_args);
self.try_normalize_erasing_regions(param_env, substituted)
}

View file

@ -360,7 +360,7 @@ pub trait PrettyPrinter<'tcx>:
self.write_str(get_local_name(&self, symbol, parent, parent_key).as_str())?;
self.write_str("::")?;
} else if let DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Trait
| DefKind::TyAlias { .. } | DefKind::Fn | DefKind::Const | DefKind::Static(_) = kind
| DefKind::TyAlias | DefKind::Fn | DefKind::Const | DefKind::Static(_) = kind
{
} else {
// If not covered above, like for example items out of `impl` blocks, fallback.
@ -766,7 +766,7 @@ pub trait PrettyPrinter<'tcx>:
let parent = self.tcx().parent(def_id);
match self.tcx().def_kind(parent) {
DefKind::TyAlias { .. } | DefKind::AssocTy => {
DefKind::TyAlias | DefKind::AssocTy => {
// NOTE: I know we should check for NO_QUERIES here, but it's alright.
// `type_of` on a type alias or assoc type should never cause a cycle.
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) =
@ -2330,7 +2330,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
// If this is an anonymous placeholder, don't rename. Otherwise, in some
// async fns, we get a `for<'r> Send` bound
match kind {
ty::BrAnon(..) | ty::BrEnv => r,
ty::BrAnon | ty::BrEnv => r,
_ => {
// Index doesn't matter, since this is just for naming and these never get bound
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
@ -2451,7 +2451,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
binder_level_idx: ty::DebruijnIndex,
br: ty::BoundRegion| {
let (name, kind) = match br.kind {
ty::BrAnon(..) | ty::BrEnv => {
ty::BrAnon | ty::BrEnv => {
let name = next_name(&self);
if let Some(lt_idx) = lifetime_idx {
@ -2998,7 +2998,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
match child.res {
def::Res::Def(DefKind::AssocTy, _) => {}
def::Res::Def(DefKind::TyAlias { .. }, _) => {}
def::Res::Def(DefKind::TyAlias, _) => {}
def::Res::Def(defkind, def_id) => {
if let Some(ns) = defkind.ns() {
collect_fn(&child.ident, ns, def_id);

View file

@ -68,7 +68,7 @@ impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
impl fmt::Debug for ty::BoundRegionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ty::BrAnon(span) => write!(f, "BrAnon({span:?})"),
ty::BrAnon => write!(f, "BrAnon"),
ty::BrNamed(did, name) => {
if did.is_crate_root() {
write!(f, "BrNamed({name})")

View file

@ -69,7 +69,7 @@ pub struct FreeRegion {
#[derive(HashStable)]
pub enum BoundRegionKind {
/// An anonymous region parameter for a given fn (&T)
BrAnon(Option<Span>),
BrAnon,
/// Named region parameters for functions (a in &'a T)
///
@ -1223,7 +1223,7 @@ impl<'tcx> AliasTy<'tcx> {
DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent,
DefKind::AssocTy => ty::Projection,
DefKind::OpaqueTy => ty::Opaque,
DefKind::TyAlias { .. } => ty::Weak,
DefKind::TyAlias => ty::Weak,
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
}
}
@ -1465,7 +1465,7 @@ impl<'tcx> Region<'tcx> {
bound_region: ty::BoundRegion,
) -> Region<'tcx> {
// Use a pre-interned one when possible.
if let ty::BoundRegion { var, kind: ty::BrAnon(None) } = bound_region
if let ty::BoundRegion { var, kind: ty::BrAnon } = bound_region
&& let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize())
&& let Some(re) = inner.get(var.as_usize()).copied()
{
@ -1959,7 +1959,7 @@ impl<'tcx> Ty<'tcx> {
(kind, tcx.def_kind(alias_ty.def_id)),
(ty::Opaque, DefKind::OpaqueTy)
| (ty::Projection | ty::Inherent, DefKind::AssocTy)
| (ty::Weak, DefKind::TyAlias { .. })
| (ty::Weak, DefKind::TyAlias)
);
Ty::new(tcx, Alias(kind, alias_ty))
}
@ -3010,7 +3010,7 @@ mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
// tidy-alphabetical-start
static_assert_size!(RegionKind<'_>, 28);
static_assert_size!(RegionKind<'_>, 24);
static_assert_size!(TyKind<'_>, 32);
// tidy-alphabetical-end
}

View file

@ -156,7 +156,7 @@ impl<'tcx> TyCtxt<'tcx> {
| DefKind::Enum
| DefKind::Trait
| DefKind::OpaqueTy
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy

View file

@ -217,7 +217,7 @@ fn find_item_ty_spans(
match ty.kind {
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
if let Res::Def(kind, def_id) = path.res
&& !matches!(kind, DefKind::TyAlias { .. }) {
&& !matches!(kind, DefKind::TyAlias) {
let check_params = def_id.as_local().map_or(true, |def_id| {
if def_id == needle {
spans.push(ty.span);

View file

@ -229,6 +229,9 @@ mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type
.suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
.help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
mir_build_non_partial_eq_match =
to use a constant of type `{$non_peq_ty}` in a pattern, the type must implement `PartialEq`
mir_build_nontrivial_structural_match =
to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`

View file

@ -748,6 +748,12 @@ pub struct NontrivialStructuralMatch<'tcx> {
pub non_sm_ty: Ty<'tcx>,
}
#[derive(LintDiagnostic)]
#[diag(mir_build_non_partial_eq_match)]
pub struct NonPartialEqMatch<'tcx> {
pub non_peq_ty: Ty<'tcx>,
}
#[derive(LintDiagnostic)]
#[diag(mir_build_overlapping_range_endpoints)]
#[note]

View file

@ -16,8 +16,8 @@ use std::cell::Cell;
use super::PatCtxt;
use crate::errors::{
FloatPattern, IndirectStructuralMatch, InvalidPattern, NontrivialStructuralMatch,
PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
FloatPattern, IndirectStructuralMatch, InvalidPattern, NonPartialEqMatch,
NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
};
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
@ -155,8 +155,9 @@ impl<'tcx> ConstToPat<'tcx> {
};
if !self.saw_const_match_error.get() {
// If we were able to successfully convert the const to some pat,
// double-check that all types in the const implement `Structural`.
// If we were able to successfully convert the const to some pat (possibly with some
// lints, but no errors), double-check that all types in the const implement
// `Structural` and `PartialEq`.
let structural =
traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty());
@ -178,7 +179,7 @@ impl<'tcx> ConstToPat<'tcx> {
}
if let Some(non_sm_ty) = structural {
if !self.type_may_have_partial_eq_impl(cv.ty()) {
if !self.type_has_partial_eq_impl(cv.ty()) {
if let ty::Adt(def, ..) = non_sm_ty.kind() {
if def.is_union() {
let err = UnionPattern { span: self.span };
@ -192,8 +193,10 @@ impl<'tcx> ConstToPat<'tcx> {
} else {
let err = InvalidPattern { span: self.span, non_sm_ty };
self.tcx().sess.emit_err(err);
return Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Wild });
}
// All branches above emitted an error. Don't print any more lints.
// The pattern we return is irrelevant since we errored.
return Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Wild });
} else if !self.saw_const_match_lint.get() {
if let Some(mir_structural_match_violation) = mir_structural_match_violation {
match non_sm_ty.kind() {
@ -238,13 +241,24 @@ impl<'tcx> ConstToPat<'tcx> {
_ => {}
}
}
// Always check for `PartialEq`, even if we emitted other lints. (But not if there were
// any errors.) This ensures it shows up in cargo's future-compat reports as well.
if !self.type_has_partial_eq_impl(cv.ty()) {
self.tcx().emit_spanned_lint(
lint::builtin::CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
self.id,
self.span,
NonPartialEqMatch { non_peq_ty: cv.ty() },
);
}
}
inlined_const_as_pat
}
#[instrument(level = "trace", skip(self), ret)]
fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
// double-check there even *is* a semantic `PartialEq` to dispatch to.
//
// (If there isn't, then we can safely issue a hard
@ -259,8 +273,13 @@ impl<'tcx> ConstToPat<'tcx> {
ty::TraitRef::new(self.tcx(), partial_eq_trait_id, [ty, ty]),
);
// FIXME: should this call a `predicate_must_hold` variant instead?
self.infcx.predicate_may_hold(&partial_eq_obligation)
// This *could* accept a type that isn't actually `PartialEq`, because region bounds get
// ignored. However that should be pretty much impossible since consts that do not depend on
// generics can only mention the `'static` lifetime, and how would one have a type that's
// `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem
// we'll need to leave some sort of trace of this requirement in the MIR so that borrowck
// can ensure that the type really implements `PartialEq`.
self.infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation)
}
fn field_pats(

View file

@ -439,7 +439,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
DefKind::Struct
| DefKind::Ctor(CtorOf::Struct, ..)
| DefKind::Union
| DefKind::TyAlias { .. }
| DefKind::TyAlias
| DefKind::AssocTy,
_,
)

View file

@ -758,7 +758,9 @@ impl Map {
self.value_count += 1;
}
if let Some(ref_ty) = ty.builtin_deref(true) && let ty::Slice(..) = ref_ty.ty.kind() {
if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ty::TypeAndMut { ty: ref_ty, .. }) = ty.kind()
&& let ty::Slice(..) = ref_ty.kind()
{
assert!(self.places[place].value_index.is_none(), "slices are not scalars");
// Prepend new child to the linked list.

View file

@ -193,7 +193,7 @@ impl<'tcx> Inliner<'tcx> {
return Err("optimization fuel exhausted");
}
let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions(
let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions(
self.tcx,
self.param_env,
ty::EarlyBinder::bind(callee_body.clone()),
@ -481,9 +481,10 @@ impl<'tcx> Inliner<'tcx> {
work_list.push(target);
// If the place doesn't actually need dropping, treat it like a regular goto.
let ty = callsite
.callee
.subst_mir(self.tcx, ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty));
let ty = callsite.callee.instantiate_mir(
self.tcx,
ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty),
);
if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind {
work_list.push(unwind);
}
@ -650,7 +651,7 @@ impl<'tcx> Inliner<'tcx> {
// Copy only unevaluated constants from the callee_body into the caller_body.
// Although we are only pushing `ConstKind::Unevaluated` consts to
// `required_consts`, here we may not only have `ConstKind::Unevaluated`
// because we are calling `subst_and_normalize_erasing_regions`.
// because we are calling `instantiate_and_normalize_erasing_regions`.
caller_body.required_consts.extend(
callee_body.required_consts.iter().copied().filter(|&ct| match ct.const_ {
Const::Ty(_) => {
@ -811,9 +812,10 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
match terminator.kind {
TerminatorKind::Drop { ref place, unwind, .. } => {
// If the place doesn't actually need dropping, treat it like a regular goto.
let ty = self
.instance
.subst_mir(tcx, ty::EarlyBinder::bind(&place.ty(self.callee_body, tcx).ty));
let ty = self.instance.instantiate_mir(
tcx,
ty::EarlyBinder::bind(&place.ty(self.callee_body, tcx).ty),
);
if ty.needs_drop(tcx, self.param_env) {
self.cost += CALL_PENALTY;
if let UnwindAction::Cleanup(_) = unwind {
@ -824,7 +826,8 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
}
}
TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.const_.ty()));
let fn_ty =
self.instance.instantiate_mir(tcx, ty::EarlyBinder::bind(&f.const_.ty()));
self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
// Don't give intrinsics the extra penalty for calls
INSTR_COST

View file

@ -44,7 +44,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
) -> bool {
trace!(%caller);
for &(callee, args) in tcx.mir_inliner_callees(caller.def) {
let Ok(args) = caller.try_subst_mir_and_normalize_erasing_regions(
let Ok(args) = caller.try_instantiate_mir_and_normalize_erasing_regions(
tcx,
param_env,
ty::EarlyBinder::bind(args),

View file

@ -29,6 +29,7 @@
use crate::MirPass;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_index::bit_set::BitSet;
use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
@ -345,24 +346,22 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let basic_blocks = body.basic_blocks.as_mut();
let source_scopes = &body.source_scopes;
let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
let mut used_blocks = 0;
for alive_index in reachable.iter() {
let alive_index = alive_index.index();
replacements[alive_index] = BasicBlock::new(used_blocks);
if alive_index != used_blocks {
// Swap the next alive block data with the current available slot. Since
// alive_index is non-decreasing this is a valid operation.
basic_blocks.raw.swap(alive_index, used_blocks);
}
used_blocks += 1;
}
if tcx.sess.instrument_coverage() {
save_unreachable_coverage(basic_blocks, source_scopes, used_blocks);
save_unreachable_coverage(basic_blocks, source_scopes, &reachable);
}
basic_blocks.raw.truncate(used_blocks);
let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
let mut orig_index = 0;
let mut used_index = 0;
basic_blocks.raw.retain(|_| {
let keep = reachable.contains(BasicBlock::new(orig_index));
if keep {
replacements[orig_index] = BasicBlock::new(used_index);
used_index += 1;
}
orig_index += 1;
keep
});
for block in basic_blocks {
for target in block.terminator_mut().successors_mut() {
@ -404,11 +403,12 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
fn save_unreachable_coverage(
basic_blocks: &mut IndexSlice<BasicBlock, BasicBlockData<'_>>,
source_scopes: &IndexSlice<SourceScope, SourceScopeData<'_>>,
first_dead_block: usize,
reachable: &BitSet<BasicBlock>,
) {
// Identify instances that still have some live coverage counters left.
let mut live = FxHashSet::default();
for basic_block in &basic_blocks.raw[0..first_dead_block] {
for bb in reachable.iter() {
let basic_block = &basic_blocks[bb];
for statement in &basic_block.statements {
let StatementKind::Coverage(coverage) = &statement.kind else { continue };
let CoverageKind::Counter { .. } = coverage.kind else { continue };
@ -417,7 +417,8 @@ fn save_unreachable_coverage(
}
}
for block in &mut basic_blocks.raw[..first_dead_block] {
for bb in reachable.iter() {
let block = &mut basic_blocks[bb];
for statement in &mut block.statements {
let StatementKind::Coverage(_) = &statement.kind else { continue };
let instance = statement.source_info.scope.inlined_instance(source_scopes);
@ -433,7 +434,11 @@ fn save_unreachable_coverage(
// Retain coverage for instances that still have some live counters left.
let mut retained_coverage = Vec::new();
for dead_block in &basic_blocks.raw[first_dead_block..] {
for dead_block in basic_blocks.indices() {
if reachable.contains(dead_block) {
continue;
}
let dead_block = &basic_blocks[dead_block];
for statement in &dead_block.statements {
let StatementKind::Coverage(coverage) = &statement.kind else { continue };
let Some(code_region) = &coverage.code_region else { continue };

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