mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-30 14:01:51 +00:00
Auto merge of #18364 - lnicola:sync-from-rust, r=lnicola
minor: sync from downstream
This commit is contained in:
commit
ca51c1e72c
17
.github/workflows/ci.yml
vendored
17
.github/workflows/ci.yml
vendored
@ -104,6 +104,18 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
# Free up disk space on Linux by removing preinstalled components that
|
||||
# we do not need. We do this to enable some of the less resource
|
||||
# intensive jobs to run on free runners, which however also have
|
||||
# less disk space.
|
||||
- name: free up disk space
|
||||
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||
if: contains(matrix.os, 'ubuntu')
|
||||
with:
|
||||
# Removing packages with APT saves ~5 GiB, but takes several
|
||||
# minutes (and potentially removes important packages).
|
||||
large-packages: false
|
||||
|
||||
# Rust Log Analyzer can't currently detect the PR number of a GitHub
|
||||
# Actions build on its own, so a hint in the log message is needed to
|
||||
# point it in the right direction.
|
||||
@ -194,6 +206,11 @@ jobs:
|
||||
- name: create github artifacts
|
||||
run: src/ci/scripts/create-doc-artifacts.sh
|
||||
|
||||
- name: print disk usage
|
||||
run: |
|
||||
echo "disk usage:"
|
||||
df -h
|
||||
|
||||
- name: upload artifacts to github
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -57,6 +57,8 @@ build/
|
||||
/src/tools/x/target
|
||||
# Created by default with `src/ci/docker/run.sh`
|
||||
/obj/
|
||||
# Created by nix dev shell / .envrc
|
||||
src/tools/nix-dev-shell/flake.lock
|
||||
|
||||
## ICE reports
|
||||
rustc-ice-*.txt
|
||||
|
1
.mailmap
1
.mailmap
@ -256,6 +256,7 @@ Jakub Adam Wieczorek <jakub.adam.wieczorek@gmail.com>
|
||||
Jakub Adam Wieczorek <jakub.adam.wieczorek@gmail.com> <jakub.bukaj@yahoo.com>
|
||||
Jakub Adam Wieczorek <jakub.adam.wieczorek@gmail.com> <jakub@jakub.cc>
|
||||
Jakub Adam Wieczorek <jakub.adam.wieczorek@gmail.com> <jakubw@jakubw.net>
|
||||
Jakub Beránek <berykubik@gmail.com> <jakub.beranek@vsb.cz>
|
||||
James [Undefined] <tpzker@thepuzzlemaker.info>
|
||||
James Deng <cnjamesdeng@gmail.com> <cnJamesDeng@gmail.com>
|
||||
James Hinshelwood <jameshinshelwood1@gmail.com> <james.hinshelwood@bigpayme.com>
|
||||
|
71
Cargo.lock
71
Cargo.lock
@ -377,7 +377,7 @@ dependencies = [
|
||||
"cargo_metadata",
|
||||
"directories",
|
||||
"rustc-build-sysroot",
|
||||
"rustc_tools_util 0.4.0",
|
||||
"rustc_tools_util",
|
||||
"rustc_version",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -537,7 +537,7 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.83"
|
||||
version = "0.1.84"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"cargo_metadata",
|
||||
@ -550,9 +550,11 @@ dependencies = [
|
||||
"if_chain",
|
||||
"itertools",
|
||||
"parking_lot",
|
||||
"pulldown-cmark 0.11.3",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc_tools_util 0.3.0",
|
||||
"rinja",
|
||||
"rustc_tools_util",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.79",
|
||||
@ -566,7 +568,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_config"
|
||||
version = "0.1.83"
|
||||
version = "0.1.84"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"serde",
|
||||
@ -582,20 +584,19 @@ dependencies = [
|
||||
"clap",
|
||||
"indoc",
|
||||
"itertools",
|
||||
"opener 0.6.1",
|
||||
"opener",
|
||||
"shell-escape",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.83"
|
||||
version = "0.1.84"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata",
|
||||
"clippy_config",
|
||||
"clippy_utils",
|
||||
"declare_clippy_lint",
|
||||
"itertools",
|
||||
"quine-mc_cluskey",
|
||||
"regex",
|
||||
@ -613,7 +614,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.83"
|
||||
version = "0.1.84"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"clippy_config",
|
||||
@ -919,15 +920,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.83"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
@ -1915,7 +1907,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"fs-err",
|
||||
"rustc-hash 1.1.0",
|
||||
"rustc-hash 2.0.0",
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -2163,7 +2155,7 @@ dependencies = [
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"opener 0.7.2",
|
||||
"opener",
|
||||
"pulldown-cmark 0.10.3",
|
||||
"regex",
|
||||
"serde",
|
||||
@ -2501,17 +2493,6 @@ dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opener"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c62dcb6174f9cb326eac248f07e955d5d559c272730b6c03e396b443b562788"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"normpath",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opener"
|
||||
version = "0.7.2"
|
||||
@ -2879,6 +2860,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"getopts",
|
||||
"memchr",
|
||||
"pulldown-cmark-escape 0.11.0",
|
||||
"unicase",
|
||||
@ -3532,7 +3514,7 @@ dependencies = [
|
||||
"memmap2",
|
||||
"parking_lot",
|
||||
"portable-atomic",
|
||||
"rustc-hash 1.1.0",
|
||||
"rustc-hash 2.0.0",
|
||||
"rustc-rayon",
|
||||
"rustc-stable-hash",
|
||||
"rustc_arena",
|
||||
@ -4229,7 +4211,7 @@ dependencies = [
|
||||
name = "rustc_pattern_analysis"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc-hash 1.1.0",
|
||||
"rustc-hash 2.0.0",
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_data_structures",
|
||||
@ -4460,12 +4442,6 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_tools_util"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_tools_util"
|
||||
version = "0.4.0"
|
||||
@ -4608,6 +4584,7 @@ dependencies = [
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"smallvec",
|
||||
"tempfile",
|
||||
"threadpool",
|
||||
@ -4632,7 +4609,7 @@ name = "rustdoc-json-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"rustc-hash 1.1.0",
|
||||
"rustc-hash 2.0.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
@ -5262,7 +5239,7 @@ dependencies = [
|
||||
"ignore",
|
||||
"miropt-test-tools",
|
||||
"regex",
|
||||
"rustc-hash 1.1.0",
|
||||
"rustc-hash 2.0.0",
|
||||
"semver",
|
||||
"similar",
|
||||
"termcolor",
|
||||
@ -5593,13 +5570,6 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bdd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ucd-parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.15"
|
||||
@ -5649,6 +5619,13 @@ version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-table-generator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ucd-parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.14"
|
||||
|
@ -3,18 +3,23 @@ mod abi {
|
||||
pub(crate) use crate::Variants;
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
use crate::{Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
|
||||
#[cfg(feature = "nightly")]
|
||||
use crate::{Abi, FieldsShape, TyAbiInterface, TyAndLayout};
|
||||
use crate::{Align, HasDataLayout, Size};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum RegKind {
|
||||
Integer,
|
||||
Float,
|
||||
Vector,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Reg {
|
||||
pub kind: RegKind,
|
||||
pub size: Size,
|
||||
@ -108,15 +113,8 @@ impl HomogeneousAggregate {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
|
||||
pub fn is_aggregate(&self) -> bool {
|
||||
match self.abi {
|
||||
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Homogeneous` if this layout is an aggregate containing fields of
|
||||
/// only a single type (e.g., `(u32, u32)`). Such aggregates are often
|
||||
/// special-cased in ABIs.
|
||||
|
@ -11,8 +11,10 @@ use crate::{
|
||||
Variants, WrappingRange,
|
||||
};
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
mod ty;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
|
||||
|
||||
// A variant is absent if it's uninhabited and only has ZST fields.
|
||||
@ -39,7 +41,7 @@ enum NicheBias {
|
||||
End,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum LayoutCalculatorError<F> {
|
||||
/// An unsized type was found in a location where a sized type was expected.
|
||||
///
|
||||
@ -54,6 +56,36 @@ pub enum LayoutCalculatorError<F> {
|
||||
|
||||
/// A union had no fields.
|
||||
EmptyUnion,
|
||||
|
||||
/// The fields or variants have irreconcilable reprs
|
||||
ReprConflict,
|
||||
}
|
||||
|
||||
impl<F> LayoutCalculatorError<F> {
|
||||
pub fn without_payload(&self) -> LayoutCalculatorError<()> {
|
||||
match self {
|
||||
LayoutCalculatorError::UnexpectedUnsized(_) => {
|
||||
LayoutCalculatorError::UnexpectedUnsized(())
|
||||
}
|
||||
LayoutCalculatorError::SizeOverflow => LayoutCalculatorError::SizeOverflow,
|
||||
LayoutCalculatorError::EmptyUnion => LayoutCalculatorError::EmptyUnion,
|
||||
LayoutCalculatorError::ReprConflict => LayoutCalculatorError::ReprConflict,
|
||||
}
|
||||
}
|
||||
|
||||
/// Format an untranslated diagnostic for this type
|
||||
///
|
||||
/// Intended for use by rust-analyzer, as neither it nor `rustc_abi` depend on fluent infra.
|
||||
pub fn fallback_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
LayoutCalculatorError::UnexpectedUnsized(_) => {
|
||||
"an unsized type was found where a sized type was expected"
|
||||
}
|
||||
LayoutCalculatorError::SizeOverflow => "size overflow",
|
||||
LayoutCalculatorError::EmptyUnion => "type is a union with no fields",
|
||||
LayoutCalculatorError::ReprConflict => "type has an invalid repr",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type LayoutCalculatorResult<FieldIdx, VariantIdx, F> =
|
||||
@ -489,6 +521,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||
}
|
||||
|
||||
let dl = self.cx.data_layout();
|
||||
// bail if the enum has an incoherent repr that cannot be computed
|
||||
if repr.packed() {
|
||||
return Err(LayoutCalculatorError::ReprConflict);
|
||||
}
|
||||
|
||||
let calculate_niche_filling_layout = || -> Option<TmpLayout<FieldIdx, VariantIdx>> {
|
||||
if dont_niche_optimize_enum {
|
||||
|
@ -29,14 +29,14 @@ mod layout;
|
||||
mod tests;
|
||||
|
||||
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
|
||||
pub use layout::{
|
||||
FIRST_VARIANT, FieldIdx, Layout, LayoutCalculator, LayoutCalculatorError, TyAbiInterface,
|
||||
TyAndLayout, VariantIdx,
|
||||
};
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
|
||||
pub use layout::{LayoutCalculator, LayoutCalculatorError};
|
||||
|
||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
/// instead of implementing everything in `rustc_middle`.
|
||||
#[cfg(feature = "nightly")]
|
||||
pub trait HashStableContext {}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Default)]
|
||||
@ -1644,6 +1644,14 @@ pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> {
|
||||
}
|
||||
|
||||
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
|
||||
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
|
||||
pub fn is_aggregate(&self) -> bool {
|
||||
match self.abi {
|
||||
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
|
||||
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
|
||||
let size = scalar.size(cx);
|
||||
|
@ -23,7 +23,6 @@
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(strict_provenance)]
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
@ -1574,7 +1574,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
.collect();
|
||||
|
||||
// Introduce extra lifetimes if late resolution tells us to.
|
||||
let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
|
||||
let extra_lifetimes = self.resolver.extra_lifetime_params(parent_node_id);
|
||||
params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
|
||||
self.lifetime_res_to_generic_param(
|
||||
ident,
|
||||
|
@ -268,8 +268,8 @@ impl ResolverAstLowering {
|
||||
///
|
||||
/// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring
|
||||
/// should appear at the enclosing `PolyTraitRef`.
|
||||
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
self.extra_lifetime_params_map.remove(&id).unwrap_or_default()
|
||||
fn extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
self.extra_lifetime_params_map.get(&id).cloned().unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
@ -885,7 +885,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let mut generic_params: Vec<_> = self
|
||||
.lower_generic_params_mut(generic_params, hir::GenericParamSource::Binder)
|
||||
.collect();
|
||||
let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
|
||||
let extra_lifetimes = self.resolver.extra_lifetime_params(binder);
|
||||
debug!(?extra_lifetimes);
|
||||
generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
|
||||
self.lifetime_res_to_generic_param(ident, node_id, res, hir::GenericParamSource::Binder)
|
||||
@ -1495,62 +1495,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// frequently opened issues show.
|
||||
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
|
||||
|
||||
let captured_lifetimes_to_duplicate = if let Some(args) =
|
||||
// We only look for one `use<...>` syntax since we syntactially reject more than one.
|
||||
bounds.iter().find_map(
|
||||
|bound| match bound {
|
||||
ast::GenericBound::Use(a, _) => Some(a),
|
||||
_ => None,
|
||||
},
|
||||
) {
|
||||
// We'll actually validate these later on; all we need is the list of
|
||||
// lifetimes to duplicate during this portion of lowering.
|
||||
args.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
PreciseCapturingArg::Lifetime(lt) => Some(*lt),
|
||||
PreciseCapturingArg::Arg(..) => None,
|
||||
})
|
||||
// Add in all the lifetimes mentioned in the bounds. We will error
|
||||
// them out later, but capturing them here is important to make sure
|
||||
// they actually get resolved in resolve_bound_vars.
|
||||
.chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds))
|
||||
.collect()
|
||||
} else {
|
||||
match origin {
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||
// type alias impl trait and associated type position impl trait were
|
||||
// decided to capture all in-scope lifetimes, which we collect for
|
||||
// all opaques during resolution.
|
||||
self.resolver
|
||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||
.into_iter()
|
||||
.map(|(ident, id, _)| Lifetime { id, ident })
|
||||
.collect()
|
||||
}
|
||||
hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => {
|
||||
if in_trait_or_impl.is_some()
|
||||
|| self.tcx.features().lifetime_capture_rules_2024
|
||||
|| span.at_least_rust_2024()
|
||||
{
|
||||
// return-position impl trait in trait was decided to capture all
|
||||
// in-scope lifetimes, which we collect for all opaques during resolution.
|
||||
self.resolver
|
||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||
.into_iter()
|
||||
.map(|(ident, id, _)| Lifetime { id, ident })
|
||||
.collect()
|
||||
} else {
|
||||
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
|
||||
// example, we only need to duplicate lifetimes that appear in the
|
||||
// bounds, since those are the only ones that are captured by the opaque.
|
||||
lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
|
||||
}
|
||||
}
|
||||
hir::OpaqueTyOrigin::AsyncFn { .. } => {
|
||||
unreachable!("should be using `lower_async_fn_ret_ty`")
|
||||
}
|
||||
// Whether this opaque always captures lifetimes in scope.
|
||||
// Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024`
|
||||
// is enabled. We don't check the span of the edition, since this is done
|
||||
// on a per-opaque basis to account for nested opaques.
|
||||
let always_capture_in_scope = match origin {
|
||||
_ if self.tcx.features().lifetime_capture_rules_2024 => true,
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => true,
|
||||
hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(),
|
||||
hir::OpaqueTyOrigin::AsyncFn { .. } => {
|
||||
unreachable!("should be using `lower_coroutine_fn_ret_ty`")
|
||||
}
|
||||
};
|
||||
let captured_lifetimes_to_duplicate = lifetime_collector::lifetimes_for_opaque(
|
||||
self.resolver,
|
||||
always_capture_in_scope,
|
||||
opaque_ty_node_id,
|
||||
bounds,
|
||||
span,
|
||||
);
|
||||
debug!(?captured_lifetimes_to_duplicate);
|
||||
|
||||
// Feature gate for RPITIT + use<..>
|
||||
@ -1920,7 +1883,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
let captured_lifetimes = self
|
||||
.resolver
|
||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||
.extra_lifetime_params(opaque_ty_node_id)
|
||||
.into_iter()
|
||||
.map(|(ident, id, _)| Lifetime { id, ident })
|
||||
.collect();
|
||||
|
@ -1,5 +1,7 @@
|
||||
use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
|
||||
use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
|
||||
use rustc_ast::{
|
||||
GenericBound, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind,
|
||||
};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Res};
|
||||
use rustc_middle::span_bug;
|
||||
@ -10,14 +12,41 @@ use rustc_span::symbol::{Ident, kw};
|
||||
use super::ResolverAstLoweringExt;
|
||||
|
||||
struct LifetimeCollectVisitor<'ast> {
|
||||
resolver: &'ast ResolverAstLowering,
|
||||
resolver: &'ast mut ResolverAstLowering,
|
||||
always_capture_in_scope: bool,
|
||||
current_binders: Vec<NodeId>,
|
||||
collected_lifetimes: FxIndexSet<Lifetime>,
|
||||
}
|
||||
|
||||
impl<'ast> LifetimeCollectVisitor<'ast> {
|
||||
fn new(resolver: &'ast ResolverAstLowering) -> Self {
|
||||
Self { resolver, current_binders: Vec::new(), collected_lifetimes: FxIndexSet::default() }
|
||||
fn new(resolver: &'ast mut ResolverAstLowering, always_capture_in_scope: bool) -> Self {
|
||||
Self {
|
||||
resolver,
|
||||
always_capture_in_scope,
|
||||
current_binders: Vec::new(),
|
||||
collected_lifetimes: FxIndexSet::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_opaque(&mut self, opaque_ty_node_id: NodeId, bounds: &'ast GenericBounds, span: Span) {
|
||||
// If we're edition 2024 or within a TAIT or RPITIT, *and* there is no
|
||||
// `use<>` statement to override the default capture behavior, then
|
||||
// capture all of the in-scope lifetimes.
|
||||
if (self.always_capture_in_scope || span.at_least_rust_2024())
|
||||
&& bounds.iter().all(|bound| !matches!(bound, GenericBound::Use(..)))
|
||||
{
|
||||
for (ident, id, _) in self.resolver.extra_lifetime_params(opaque_ty_node_id) {
|
||||
self.record_lifetime_use(Lifetime { id, ident });
|
||||
}
|
||||
}
|
||||
|
||||
// We also recurse on the bounds to make sure we capture all the lifetimes
|
||||
// mentioned in the bounds. These may disagree with the `use<>` list, in which
|
||||
// case we will error on these later. We will also recurse to visit any
|
||||
// nested opaques, which may *implicitly* capture lifetimes.
|
||||
for bound in bounds {
|
||||
self.visit_param_bound(bound, BoundKind::Bound);
|
||||
}
|
||||
}
|
||||
|
||||
fn record_lifetime_use(&mut self, lifetime: Lifetime) {
|
||||
@ -99,6 +128,9 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
|
||||
self.record_elided_anchor(t.id, t.span);
|
||||
visit::walk_ty(self, t);
|
||||
}
|
||||
TyKind::ImplTrait(opaque_ty_node_id, bounds) => {
|
||||
self.visit_opaque(*opaque_ty_node_id, bounds, t.span)
|
||||
}
|
||||
_ => {
|
||||
visit::walk_ty(self, t);
|
||||
}
|
||||
@ -106,13 +138,14 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lifetimes_in_bounds(
|
||||
resolver: &ResolverAstLowering,
|
||||
pub(crate) fn lifetimes_for_opaque(
|
||||
resolver: &mut ResolverAstLowering,
|
||||
always_capture_in_scope: bool,
|
||||
opaque_ty_node_id: NodeId,
|
||||
bounds: &GenericBounds,
|
||||
span: Span,
|
||||
) -> FxIndexSet<Lifetime> {
|
||||
let mut visitor = LifetimeCollectVisitor::new(resolver);
|
||||
for bound in bounds {
|
||||
visitor.visit_param_bound(bound, BoundKind::Bound);
|
||||
}
|
||||
let mut visitor = LifetimeCollectVisitor::new(resolver, always_capture_in_scope);
|
||||
visitor.visit_opaque(opaque_ty_node_id, bounds, span);
|
||||
visitor.collected_lifetimes
|
||||
}
|
||||
|
@ -3,12 +3,16 @@ use std::rc::Rc;
|
||||
|
||||
use rustc_errors::Diag;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::canonical::CanonicalQueryInput;
|
||||
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt as _,
|
||||
};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_infer::traits::query::{
|
||||
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpNormalizeGoal,
|
||||
CanonicalTypeOpProvePredicateGoal,
|
||||
};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::{
|
||||
self, RePlaceholder, Region, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex,
|
||||
@ -95,9 +99,7 @@ impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tc
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToUniverseInfo<'tcx>
|
||||
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
|
||||
{
|
||||
impl<'tcx> ToUniverseInfo<'tcx> for CanonicalTypeOpProvePredicateGoal<'tcx> {
|
||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
|
||||
canonical_query: self,
|
||||
@ -107,7 +109,7 @@ impl<'tcx> ToUniverseInfo<'tcx>
|
||||
}
|
||||
|
||||
impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx> ToUniverseInfo<'tcx>
|
||||
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
|
||||
for CanonicalTypeOpNormalizeGoal<'tcx, T>
|
||||
{
|
||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
|
||||
@ -117,9 +119,7 @@ impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx> ToUnivers
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToUniverseInfo<'tcx>
|
||||
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
|
||||
{
|
||||
impl<'tcx> ToUniverseInfo<'tcx> for CanonicalTypeOpAscribeUserTypeGoal<'tcx> {
|
||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
|
||||
canonical_query: self,
|
||||
@ -128,7 +128,7 @@ impl<'tcx> ToUniverseInfo<'tcx>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, F> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F>> {
|
||||
impl<'tcx, F> ToUniverseInfo<'tcx> for CanonicalQueryInput<'tcx, type_op::custom::CustomTypeOp<F>> {
|
||||
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
// We can't rerun custom type ops.
|
||||
UniverseInfo::other()
|
||||
@ -211,8 +211,7 @@ trait TypeOpInfo<'tcx> {
|
||||
}
|
||||
|
||||
struct PredicateQuery<'tcx> {
|
||||
canonical_query:
|
||||
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
|
||||
canonical_query: CanonicalTypeOpProvePredicateGoal<'tcx>,
|
||||
base_universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
@ -220,7 +219,7 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
|
||||
tcx.dcx().create_err(HigherRankedLifetimeError {
|
||||
cause: Some(HigherRankedErrorCause::CouldNotProve {
|
||||
predicate: self.canonical_query.value.value.predicate.to_string(),
|
||||
predicate: self.canonical_query.canonical.value.value.predicate.to_string(),
|
||||
}),
|
||||
span,
|
||||
})
|
||||
@ -253,7 +252,7 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
||||
}
|
||||
|
||||
struct NormalizeQuery<'tcx, T> {
|
||||
canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
|
||||
canonical_query: CanonicalTypeOpNormalizeGoal<'tcx, T>,
|
||||
base_universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
@ -264,7 +263,7 @@ where
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
|
||||
tcx.dcx().create_err(HigherRankedLifetimeError {
|
||||
cause: Some(HigherRankedErrorCause::CouldNotNormalize {
|
||||
value: self.canonical_query.value.value.value.to_string(),
|
||||
value: self.canonical_query.canonical.value.value.value.to_string(),
|
||||
}),
|
||||
span,
|
||||
})
|
||||
@ -306,7 +305,7 @@ where
|
||||
}
|
||||
|
||||
struct AscribeUserTypeQuery<'tcx> {
|
||||
canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
|
||||
canonical_query: CanonicalTypeOpAscribeUserTypeGoal<'tcx>,
|
||||
base_universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
|
@ -1146,6 +1146,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
}
|
||||
// don't create labels for compiler-generated spans
|
||||
Some(_) => None,
|
||||
// don't create labels for the span not from user's code
|
||||
None if opt_assignment_rhs_span
|
||||
.is_some_and(|span| self.infcx.tcx.sess.source_map().is_imported(span)) =>
|
||||
{
|
||||
None
|
||||
}
|
||||
None => {
|
||||
let (has_sugg, decl_span, sugg) = if name != kw::SelfLower {
|
||||
suggest_ampmut(
|
||||
@ -1198,18 +1204,21 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
sugg.push(s);
|
||||
}
|
||||
|
||||
err.multipart_suggestion_verbose(
|
||||
format!(
|
||||
"consider changing this to be a mutable {pointer_desc}{}",
|
||||
if is_trait_sig {
|
||||
" in the `impl` method and the `trait` definition"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
),
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if sugg.iter().all(|(span, _)| !self.infcx.tcx.sess.source_map().is_imported(*span))
|
||||
{
|
||||
err.multipart_suggestion_verbose(
|
||||
format!(
|
||||
"consider changing this to be a mutable {pointer_desc}{}",
|
||||
if is_trait_sig {
|
||||
" in the `impl` method and the `trait` definition"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
),
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
Some((false, err_label_span, message, _)) => {
|
||||
let def_id = self.body.source.def_id();
|
||||
|
@ -187,10 +187,10 @@ fn do_mir_borrowck<'tcx>(
|
||||
|
||||
let location_table = LocationTable::new(body);
|
||||
|
||||
let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
|
||||
let move_data = MoveData::gather_moves(body, tcx, |_| true);
|
||||
let promoted_move_data = promoted
|
||||
.iter_enumerated()
|
||||
.map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, param_env, |_| true)));
|
||||
.map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true)));
|
||||
|
||||
let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
|
@ -137,7 +137,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
||||
locations,
|
||||
category,
|
||||
param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
|
||||
param_env.and(type_op::prove_predicate::ProvePredicate { predicate }),
|
||||
);
|
||||
}
|
||||
|
||||
@ -162,7 +162,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
||||
location.to_locations(),
|
||||
category,
|
||||
param_env.and(type_op::normalize::Normalize::new(value)),
|
||||
param_env.and(type_op::normalize::Normalize { value }),
|
||||
);
|
||||
result.unwrap_or(value)
|
||||
}
|
||||
@ -223,7 +223,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
||||
Locations::All(span),
|
||||
ConstraintCategory::Boring,
|
||||
self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)),
|
||||
self.param_env.and(type_op::ascribe_user_type::AscribeUserType { mir_ty, user_ty }),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -280,7 +280,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
}
|
||||
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
|
||||
.param_env
|
||||
.and(type_op::normalize::Normalize::new(ty))
|
||||
.and(type_op::normalize::Normalize { value: ty })
|
||||
.fully_perform(self.infcx, span)
|
||||
.unwrap_or_else(|guar| TypeOpOutput {
|
||||
output: Ty::new_error(self.infcx.tcx, guar),
|
||||
@ -318,7 +318,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
|
||||
let result: Result<_, ErrorGuaranteed> = self
|
||||
.param_env
|
||||
.and(type_op::normalize::Normalize::new(ty))
|
||||
.and(type_op::normalize::Normalize { value: ty })
|
||||
.fully_perform(self.infcx, span);
|
||||
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
|
||||
continue;
|
||||
@ -373,7 +373,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
|
||||
let TypeOpOutput { output: bounds, constraints, .. } = self
|
||||
.param_env
|
||||
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
|
||||
.and(type_op::ImpliedOutlivesBounds { ty })
|
||||
.fully_perform(self.infcx, span)
|
||||
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
|
||||
.ok()?;
|
||||
|
@ -11,8 +11,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
||||
use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
|
||||
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
|
||||
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
||||
use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOp, TypeOpOutput};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::location::RichLocation;
|
||||
@ -632,7 +631,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
||||
|
||||
match typeck
|
||||
.param_env
|
||||
.and(DropckOutlives::new(dropped_ty))
|
||||
.and(DropckOutlives { dropped_ty })
|
||||
.fully_perform(typeck.infcx, DUMMY_SP)
|
||||
{
|
||||
Ok(TypeOpOutput { output, constraints, .. }) => {
|
||||
|
@ -1128,7 +1128,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
let projected_ty = curr_projected_ty.projection_ty_core(
|
||||
tcx,
|
||||
self.param_env,
|
||||
proj,
|
||||
|this, field, ()| {
|
||||
let ty = this.field_ty(tcx, field);
|
||||
@ -1919,7 +1918,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// than 1.
|
||||
// If the length is larger than 1, the repeat expression will need to copy the
|
||||
// element, so we require the `Copy` trait.
|
||||
if len.try_eval_target_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
|
||||
if len.try_to_target_usize(tcx).is_none_or(|len| len > 1) {
|
||||
match operand {
|
||||
Operand::Copy(..) | Operand::Constant(..) => {
|
||||
// These are always okay: direct use of a const, or a value that can evidently be copied.
|
||||
|
@ -133,6 +133,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
||||
.expect_const()
|
||||
.try_to_valtree()
|
||||
.expect("expected monomorphic const in codegen")
|
||||
.0
|
||||
.unwrap_branch();
|
||||
|
||||
assert_eq!(x.layout(), y.layout());
|
||||
@ -806,8 +807,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
||||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => m.load_scalar(fx),
|
||||
ty::Array(elem, len)
|
||||
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) =>
|
||||
&& len
|
||||
.try_to_target_usize(fx.tcx)
|
||||
.expect("expected monomorphic const in codegen")
|
||||
== expected_bytes =>
|
||||
{
|
||||
m.force_stack(fx).0.load(
|
||||
fx,
|
||||
@ -907,8 +910,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
||||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {}
|
||||
ty::Array(elem, len)
|
||||
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) => {}
|
||||
&& len
|
||||
.try_to_target_usize(fx.tcx)
|
||||
.expect("expected monomorphic const in codegen")
|
||||
== expected_bytes => {}
|
||||
_ => {
|
||||
fx.tcx.dcx().span_fatal(
|
||||
span,
|
||||
|
@ -34,7 +34,9 @@ pub(crate) fn unsized_info<'tcx>(
|
||||
{
|
||||
let old_info =
|
||||
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
|
||||
if data_a.principal_def_id() == data_b.principal_def_id() {
|
||||
let b_principal_def_id = data_b.principal_def_id();
|
||||
if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
|
||||
// A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables.
|
||||
debug_assert!(
|
||||
validate_trivial_unsize(fx.tcx, data_a, data_b),
|
||||
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
|
||||
|
@ -76,8 +76,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
||||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
|
||||
ty::Array(elem, len)
|
||||
if matches!(*elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) =>
|
||||
&& len
|
||||
.try_to_target_usize(bx.tcx)
|
||||
.expect("expected monomorphic const in codegen")
|
||||
== expected_bytes =>
|
||||
{
|
||||
let place = PlaceRef::alloca(bx, args[0].layout);
|
||||
args[0].val.store(bx, place);
|
||||
@ -696,8 +698,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
||||
}
|
||||
ty::Array(elem, len)
|
||||
if matches!(*elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) =>
|
||||
&& len
|
||||
.try_to_target_usize(bx.tcx)
|
||||
.expect("expected monomorphic const in codegen")
|
||||
== expected_bytes =>
|
||||
{
|
||||
// Zero-extend iN to the array length:
|
||||
let ze = bx.zext(result, bx.type_ix(expected_bytes * 8));
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::ffi::CStr;
|
||||
|
||||
use itertools::Itertools as _;
|
||||
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
@ -132,7 +134,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
||||
.collect::<Vec<_>>();
|
||||
let initializer = cx.const_array(cx.type_ptr(), &name_globals);
|
||||
|
||||
let array = llvm::add_global(cx.llmod, cx.val_ty(initializer), "__llvm_coverage_names");
|
||||
let array = llvm::add_global(cx.llmod, cx.val_ty(initializer), c"__llvm_coverage_names");
|
||||
llvm::set_global_constant(array, true);
|
||||
llvm::set_linkage(array, llvm::Linkage::InternalLinkage);
|
||||
llvm::set_initializer(array, initializer);
|
||||
@ -305,7 +307,7 @@ fn generate_coverage_map<'ll>(
|
||||
/// specific, well-known section and name.
|
||||
fn save_function_record(
|
||||
cx: &CodegenCx<'_, '_>,
|
||||
covfun_section_name: &str,
|
||||
covfun_section_name: &CStr,
|
||||
mangled_function_name: &str,
|
||||
source_hash: u64,
|
||||
filenames_ref: u64,
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
use libc::c_uint;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
@ -12,6 +13,7 @@ use rustc_middle::mir::coverage::CoverageKind;
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::layout::HasTyCtxt;
|
||||
use rustc_target::abi::{Align, Size};
|
||||
use rustc_target::spec::HasTargetSpec;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::builder::Builder;
|
||||
@ -284,16 +286,16 @@ pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
cov_data_val: &'ll llvm::Value,
|
||||
) {
|
||||
let covmap_var_name = llvm::build_string(|s| unsafe {
|
||||
let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
|
||||
})
|
||||
.expect("Rust Coverage Mapping var name failed UTF-8 conversion");
|
||||
}))
|
||||
.unwrap();
|
||||
debug!("covmap var name: {:?}", covmap_var_name);
|
||||
|
||||
let covmap_section_name = llvm::build_string(|s| unsafe {
|
||||
let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
|
||||
})
|
||||
.expect("Rust Coverage section name failed UTF-8 conversion");
|
||||
}))
|
||||
.expect("covmap section name should not contain NUL");
|
||||
debug!("covmap section name: {:?}", covmap_section_name);
|
||||
|
||||
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
|
||||
@ -308,7 +310,7 @@ pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
|
||||
|
||||
pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
covfun_section_name: &str,
|
||||
covfun_section_name: &CStr,
|
||||
func_name_hash: u64,
|
||||
func_record_val: &'ll llvm::Value,
|
||||
is_used: bool,
|
||||
@ -322,7 +324,8 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
|
||||
// of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by
|
||||
// appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging.
|
||||
let func_record_var_name =
|
||||
format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" });
|
||||
CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
|
||||
.unwrap();
|
||||
debug!("function record var name: {:?}", func_record_var_name);
|
||||
debug!("function record section name: {:?}", covfun_section_name);
|
||||
|
||||
@ -334,7 +337,9 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
|
||||
llvm::set_section(llglobal, covfun_section_name);
|
||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
||||
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
|
||||
if cx.target_spec().supports_comdat() {
|
||||
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
|
||||
}
|
||||
cx.add_used_global(llglobal);
|
||||
}
|
||||
|
||||
@ -349,9 +354,9 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
|
||||
/// - `__llvm_covfun` on Linux
|
||||
/// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix)
|
||||
/// - `.lcovfun$M` on Windows (includes `$M` sorting suffix)
|
||||
pub(crate) fn covfun_section_name(cx: &CodegenCx<'_, '_>) -> String {
|
||||
llvm::build_string(|s| unsafe {
|
||||
pub(crate) fn covfun_section_name(cx: &CodegenCx<'_, '_>) -> CString {
|
||||
CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
llvm::LLVMRustCoverageWriteFuncSectionNameToString(cx.llmod, s);
|
||||
})
|
||||
.expect("Rust Coverage function record section name failed UTF-8 conversion")
|
||||
}))
|
||||
.expect("covfun section name should not contain NUL")
|
||||
}
|
||||
|
@ -787,7 +787,9 @@ fn codegen_msvc_try<'ll>(
|
||||
let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
|
||||
unsafe {
|
||||
llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
|
||||
llvm::SetUniqueComdat(bx.llmod, tydesc);
|
||||
if bx.cx.tcx.sess.target.supports_comdat() {
|
||||
llvm::SetUniqueComdat(bx.llmod, tydesc);
|
||||
}
|
||||
llvm::LLVMSetInitializer(tydesc, type_info);
|
||||
}
|
||||
|
||||
@ -1177,8 +1179,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
|
||||
ty::Array(elem, len)
|
||||
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) =>
|
||||
&& len
|
||||
.try_to_target_usize(bx.tcx)
|
||||
.expect("expected monomorphic const in codegen")
|
||||
== expected_bytes =>
|
||||
{
|
||||
let place = PlaceRef::alloca(bx, args[0].layout);
|
||||
args[0].val.store(bx, place);
|
||||
@ -1243,12 +1247,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
}
|
||||
|
||||
if name == sym::simd_shuffle_generic {
|
||||
let idx = fn_args[2]
|
||||
.expect_const()
|
||||
.eval(tcx, ty::ParamEnv::reveal_all(), span)
|
||||
.unwrap()
|
||||
.1
|
||||
.unwrap_branch();
|
||||
let idx = fn_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch();
|
||||
let n = idx.len() as u64;
|
||||
|
||||
let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn);
|
||||
@ -1467,8 +1466,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
}
|
||||
ty::Array(elem, len)
|
||||
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) =>
|
||||
&& len
|
||||
.try_to_target_usize(bx.tcx)
|
||||
.expect("expected monomorphic const in codegen")
|
||||
== expected_bytes =>
|
||||
{
|
||||
// Zero-extend iN to the array length:
|
||||
let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8));
|
||||
|
@ -646,6 +646,7 @@ unsafe extern "C" {
|
||||
pub type Attribute;
|
||||
pub type Metadata;
|
||||
pub type BasicBlock;
|
||||
pub type Comdat;
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct Builder<'a>(InvariantOpaque<'a>);
|
||||
@ -1490,6 +1491,9 @@ unsafe extern "C" {
|
||||
pub fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr);
|
||||
|
||||
pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>;
|
||||
|
||||
pub fn LLVMGetOrInsertComdat(M: &Module, Name: *const c_char) -> &Comdat;
|
||||
pub fn LLVMSetComdat(V: &Value, C: &Comdat);
|
||||
}
|
||||
|
||||
#[link(name = "llvm-wrapper", kind = "static")]
|
||||
@ -2320,7 +2324,6 @@ unsafe extern "C" {
|
||||
|
||||
pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock);
|
||||
|
||||
pub fn LLVMRustSetComdat<'a>(M: &'a Module, V: &'a Value, Name: *const c_char, NameLen: size_t);
|
||||
pub fn LLVMRustSetModulePICLevel(M: &Module);
|
||||
pub fn LLVMRustSetModulePIELevel(M: &Module);
|
||||
pub fn LLVMRustSetModuleCodeModel(M: &Module, Model: CodeModel);
|
||||
|
@ -178,10 +178,10 @@ pub fn SetFunctionCallConv(fn_: &Value, cc: CallConv) {
|
||||
// function.
|
||||
// For more details on COMDAT sections see e.g., https://www.airs.com/blog/archives/52
|
||||
pub fn SetUniqueComdat(llmod: &Module, val: &Value) {
|
||||
unsafe {
|
||||
let name = get_value_name(val);
|
||||
LLVMRustSetComdat(llmod, val, name.as_ptr().cast(), name.len());
|
||||
}
|
||||
let name_buf = get_value_name(val).to_vec();
|
||||
let name =
|
||||
CString::from_vec_with_nul(name_buf).or_else(|buf| CString::new(buf.into_bytes())).unwrap();
|
||||
set_comdat(llmod, val, &name);
|
||||
}
|
||||
|
||||
pub fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) {
|
||||
@ -210,15 +210,13 @@ impl MemoryEffects {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_section(llglobal: &Value, section_name: &str) {
|
||||
let section_name_cstr = CString::new(section_name).expect("unexpected CString error");
|
||||
pub fn set_section(llglobal: &Value, section_name: &CStr) {
|
||||
unsafe {
|
||||
LLVMSetSection(llglobal, section_name_cstr.as_ptr());
|
||||
LLVMSetSection(llglobal, section_name.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_global<'a>(llmod: &'a Module, ty: &'a Type, name: &str) -> &'a Value {
|
||||
let name_cstr = CString::new(name).expect("unexpected CString error");
|
||||
pub fn add_global<'a>(llmod: &'a Module, ty: &'a Type, name_cstr: &CStr) -> &'a Value {
|
||||
unsafe { LLVMAddGlobal(llmod, ty, name_cstr.as_ptr()) }
|
||||
}
|
||||
|
||||
@ -252,9 +250,14 @@ pub fn set_alignment(llglobal: &Value, align: Align) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_comdat(llmod: &Module, llglobal: &Value, name: &str) {
|
||||
/// Get the `name`d comdat from `llmod` and assign it to `llglobal`.
|
||||
///
|
||||
/// Inserts the comdat into `llmod` if it does not exist.
|
||||
/// It is an error to call this if the target does not support comdat.
|
||||
pub fn set_comdat(llmod: &Module, llglobal: &Value, name: &CStr) {
|
||||
unsafe {
|
||||
LLVMRustSetComdat(llmod, llglobal, name.as_ptr().cast(), name.len());
|
||||
let comdat = LLVMGetOrInsertComdat(llmod, name.as_ptr());
|
||||
LLVMSetComdat(llglobal, comdat);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,9 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
||||
unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
|
||||
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
|
||||
base::set_link_section(lldecl, attrs);
|
||||
if linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR {
|
||||
if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR)
|
||||
&& self.tcx.sess.target.supports_comdat()
|
||||
{
|
||||
llvm::SetUniqueComdat(self.llmod, lldecl);
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ pub fn validate_trivial_unsize<'tcx>(
|
||||
infcx.leak_check(universe, None).is_ok()
|
||||
})
|
||||
}
|
||||
(None, None) => true,
|
||||
(_, None) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -175,7 +175,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
{
|
||||
let old_info =
|
||||
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
|
||||
if data_a.principal_def_id() == data_b.principal_def_id() {
|
||||
let b_principal_def_id = data_b.principal_def_id();
|
||||
if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
|
||||
// Codegen takes advantage of the additional assumption, where if the
|
||||
// principal trait def id of what's being casted doesn't change,
|
||||
// then we don't need to adjust the vtable at all. This
|
||||
|
@ -23,7 +23,6 @@ use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
|
||||
use rustc_middle::ty::{
|
||||
self, ExistentialProjection, GenericArgKind, GenericArgsRef, ParamEnv, Ty, TyCtxt,
|
||||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::abi::Integer;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
@ -685,21 +684,25 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
|
||||
ty::ConstKind::Param(param) => {
|
||||
write!(output, "{}", param.name)
|
||||
}
|
||||
ty::ConstKind::Value(ty, _) => {
|
||||
ty::ConstKind::Value(ty, valtree) => {
|
||||
match ty.kind() {
|
||||
ty::Int(ity) => {
|
||||
// FIXME: directly extract the bits from a valtree instead of evaluating an
|
||||
// already evaluated `Const` in order to get the bits.
|
||||
let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||
let bits = ct
|
||||
.try_to_bits(tcx, ty::ParamEnv::reveal_all())
|
||||
.expect("expected monomorphic const in codegen");
|
||||
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
|
||||
write!(output, "{val}")
|
||||
}
|
||||
ty::Uint(_) => {
|
||||
let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||
let val = ct
|
||||
.try_to_bits(tcx, ty::ParamEnv::reveal_all())
|
||||
.expect("expected monomorphic const in codegen");
|
||||
write!(output, "{val}")
|
||||
}
|
||||
ty::Bool => {
|
||||
let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap();
|
||||
let val = ct.try_to_bool().expect("expected monomorphic const in codegen");
|
||||
write!(output, "{val}")
|
||||
}
|
||||
_ => {
|
||||
@ -711,8 +714,9 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
|
||||
// avoiding collisions and will make the emitted type names shorter.
|
||||
let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut hasher = StableHasher::new();
|
||||
let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP).unwrap();
|
||||
hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher));
|
||||
hcx.while_hashing_spans(false, |hcx| {
|
||||
(ty, valtree).hash_stable(hcx, &mut hasher)
|
||||
});
|
||||
hasher.finish::<Hash64>()
|
||||
});
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
#![feature(let_chains)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(try_blocks)]
|
||||
#![warn(unreachable_pub)]
|
||||
|
@ -361,12 +361,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
|
||||
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
|
||||
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
|
||||
(Pointer(..), Int(..)) => bx.ptrtoint(imm, to_backend_ty),
|
||||
(Pointer(..), Int(..)) => {
|
||||
// FIXME: this exposes the provenance, which shouldn't be necessary.
|
||||
bx.ptrtoint(imm, to_backend_ty)
|
||||
}
|
||||
(Float(_), Pointer(..)) => {
|
||||
let int_imm = bx.bitcast(imm, bx.cx().type_isize());
|
||||
bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
|
||||
}
|
||||
(Pointer(..), Float(_)) => {
|
||||
// FIXME: this exposes the provenance, which shouldn't be necessary.
|
||||
let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
|
||||
bx.bitcast(int_imm, to_backend_ty)
|
||||
}
|
||||
|
@ -6,13 +6,10 @@ use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::traits::BuiltinImplSource;
|
||||
use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
|
||||
use rustc_middle::{bug, mir};
|
||||
use rustc_trait_selection::traits::{
|
||||
ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
|
||||
};
|
||||
use tracing::{instrument, trace};
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||
use tracing::instrument;
|
||||
|
||||
use super::ConstCx;
|
||||
|
||||
@ -195,50 +192,8 @@ impl Qualif for NeedsNonConstDrop {
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME(effects): If `destruct` is not a `const_trait`,
|
||||
// or effects are disabled in this crate, then give up.
|
||||
let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span));
|
||||
if !cx.tcx.has_host_param(destruct_def_id) || !cx.tcx.features().effects {
|
||||
return NeedsDrop::in_any_value_of_ty(cx, ty);
|
||||
}
|
||||
|
||||
let obligation = Obligation::new(
|
||||
cx.tcx,
|
||||
ObligationCause::dummy_with_span(cx.body.span),
|
||||
cx.param_env,
|
||||
ty::TraitRef::new(cx.tcx, destruct_def_id, [
|
||||
ty::GenericArg::from(ty),
|
||||
ty::GenericArg::from(cx.tcx.expected_host_effect_param_for_body(cx.def_id())),
|
||||
]),
|
||||
);
|
||||
|
||||
let infcx = cx.tcx.infer_ctxt().build();
|
||||
let mut selcx = SelectionContext::new(&infcx);
|
||||
let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
|
||||
// If we couldn't select a const destruct candidate, then it's bad
|
||||
return true;
|
||||
};
|
||||
|
||||
trace!(?impl_src);
|
||||
|
||||
if !matches!(
|
||||
impl_src,
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(_)
|
||||
) {
|
||||
// If our const destruct candidate is not ConstDestruct or implied by the param env,
|
||||
// then it's bad
|
||||
return true;
|
||||
}
|
||||
|
||||
if impl_src.borrow_nested_obligations().is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we had any errors, then it's bad
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
ocx.register_obligations(impl_src.nested_obligations());
|
||||
let errors = ocx.select_all_or_error();
|
||||
!errors.is_empty()
|
||||
// FIXME(effects): Reimplement const drop checking.
|
||||
NeedsDrop::in_any_value_of_ty(cx, ty)
|
||||
}
|
||||
|
||||
fn in_adt_inherently<'tcx>(
|
||||
|
@ -11,7 +11,8 @@ use rustc_span::{Span, Symbol};
|
||||
use super::CompileTimeMachine;
|
||||
use crate::errors::{self, FrameNote, ReportErrorExt};
|
||||
use crate::interpret::{
|
||||
ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType, err_inval, err_machine_stop,
|
||||
ErrorHandled, Frame, InterpErrorInfo, InterpErrorKind, MachineStopType, err_inval,
|
||||
err_machine_stop,
|
||||
};
|
||||
|
||||
/// The CTFE machine has some custom error kinds.
|
||||
@ -57,7 +58,7 @@ impl MachineStopType for ConstEvalErrKind {
|
||||
}
|
||||
}
|
||||
|
||||
/// The errors become [`InterpError::MachineStop`] when being raised.
|
||||
/// The errors become [`InterpErrorKind::MachineStop`] when being raised.
|
||||
impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
|
||||
fn into(self) -> InterpErrorInfo<'tcx> {
|
||||
err_machine_stop!(self).into()
|
||||
@ -124,7 +125,7 @@ pub fn get_span_and_frames<'tcx>(
|
||||
/// `get_span_and_frames`.
|
||||
pub(super) fn report<'tcx, C, F, E>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
error: InterpError<'tcx>,
|
||||
error: InterpErrorKind<'tcx>,
|
||||
span: Span,
|
||||
get_span_and_frames: C,
|
||||
mk: F,
|
||||
|
@ -18,7 +18,7 @@ use tracing::{debug, instrument, trace};
|
||||
use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine};
|
||||
use crate::const_eval::CheckAlignment;
|
||||
use crate::interpret::{
|
||||
CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpError,
|
||||
CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpErrorKind,
|
||||
InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, create_static_alloc,
|
||||
eval_nullary_intrinsic, intern_const_alloc_recursive, interp_ok, throw_exhaust,
|
||||
};
|
||||
@ -463,7 +463,7 @@ fn report_validation_error<'tcx>(
|
||||
error: InterpErrorInfo<'tcx>,
|
||||
alloc_id: AllocId,
|
||||
) -> ErrorHandled {
|
||||
if !matches!(error.kind(), InterpError::UndefinedBehavior(_)) {
|
||||
if !matches!(error.kind(), InterpErrorKind::UndefinedBehavior(_)) {
|
||||
// Some other error happened during validation, e.g. an unsupported operation.
|
||||
return report_eval_error(ecx, cid, error);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
|
||||
|
||||
// We go to `usize` as we cannot allocate anything bigger anyway.
|
||||
let (field_count, variant, down) = match ty.kind() {
|
||||
ty::Array(_, len) => (len.eval_target_usize(tcx.tcx, param_env) as usize, None, op),
|
||||
ty::Array(_, len) => (len.try_to_target_usize(tcx.tcx)? as usize, None, op),
|
||||
ty::Adt(def, _) if def.variants().is_empty() => {
|
||||
return None;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use rustc_errors::{
|
||||
use rustc_hir::ConstContext;
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::mir::interpret::{
|
||||
CheckInAllocMsg, CtfeProvenance, ExpectedKind, InterpError, InvalidMetaKind,
|
||||
CheckInAllocMsg, CtfeProvenance, ExpectedKind, InterpErrorKind, InvalidMetaKind,
|
||||
InvalidProgramInfo, Misalignment, Pointer, PointerKind, ResourceExhaustionInfo,
|
||||
UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
|
||||
};
|
||||
@ -835,23 +835,23 @@ impl ReportErrorExt for UnsupportedOpInfo {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReportErrorExt for InterpError<'tcx> {
|
||||
impl<'tcx> ReportErrorExt for InterpErrorKind<'tcx> {
|
||||
fn diagnostic_message(&self) -> DiagMessage {
|
||||
match self {
|
||||
InterpError::UndefinedBehavior(ub) => ub.diagnostic_message(),
|
||||
InterpError::Unsupported(e) => e.diagnostic_message(),
|
||||
InterpError::InvalidProgram(e) => e.diagnostic_message(),
|
||||
InterpError::ResourceExhaustion(e) => e.diagnostic_message(),
|
||||
InterpError::MachineStop(e) => e.diagnostic_message(),
|
||||
InterpErrorKind::UndefinedBehavior(ub) => ub.diagnostic_message(),
|
||||
InterpErrorKind::Unsupported(e) => e.diagnostic_message(),
|
||||
InterpErrorKind::InvalidProgram(e) => e.diagnostic_message(),
|
||||
InterpErrorKind::ResourceExhaustion(e) => e.diagnostic_message(),
|
||||
InterpErrorKind::MachineStop(e) => e.diagnostic_message(),
|
||||
}
|
||||
}
|
||||
fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
match self {
|
||||
InterpError::UndefinedBehavior(ub) => ub.add_args(diag),
|
||||
InterpError::Unsupported(e) => e.add_args(diag),
|
||||
InterpError::InvalidProgram(e) => e.add_args(diag),
|
||||
InterpError::ResourceExhaustion(e) => e.add_args(diag),
|
||||
InterpError::MachineStop(e) => e.add_args(&mut |name, value| {
|
||||
InterpErrorKind::UndefinedBehavior(ub) => ub.add_args(diag),
|
||||
InterpErrorKind::Unsupported(e) => e.add_args(diag),
|
||||
InterpErrorKind::InvalidProgram(e) => e.add_args(diag),
|
||||
InterpErrorKind::ResourceExhaustion(e) => e.add_args(diag),
|
||||
InterpErrorKind::MachineStop(e) => e.add_args(&mut |name, value| {
|
||||
diag.arg(name, value);
|
||||
}),
|
||||
}
|
||||
|
@ -471,7 +471,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
// Don't forget to mark "initially live" locals as live.
|
||||
self.storage_live_for_always_live_locals()?;
|
||||
};
|
||||
res.inspect_err(|_| {
|
||||
res.inspect_err_kind(|_| {
|
||||
// Don't show the incomplete stack frame in the error stacktrace.
|
||||
self.stack_mut().pop();
|
||||
})
|
||||
|
@ -391,7 +391,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
let ptr = self.read_pointer(src)?;
|
||||
let val = Immediate::new_slice(
|
||||
ptr,
|
||||
length.eval_target_usize(*self.tcx, self.param_env),
|
||||
length
|
||||
.try_to_target_usize(*self.tcx)
|
||||
.expect("expected monomorphic const in const eval"),
|
||||
self,
|
||||
);
|
||||
self.write_immediate(val, dest)
|
||||
|
@ -19,7 +19,7 @@ use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use super::{
|
||||
Frame, FrameInfo, GlobalId, InterpError, InterpErrorInfo, InterpResult, MPlaceTy, Machine,
|
||||
Frame, FrameInfo, GlobalId, InterpErrorInfo, InterpErrorKind, InterpResult, MPlaceTy, Machine,
|
||||
MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance,
|
||||
err_inval, interp_ok, throw_inval, throw_ub, throw_ub_custom,
|
||||
};
|
||||
@ -73,7 +73,7 @@ where
|
||||
}
|
||||
|
||||
impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> {
|
||||
type LayoutOfResult = Result<TyAndLayout<'tcx>, InterpError<'tcx>>;
|
||||
type LayoutOfResult = Result<TyAndLayout<'tcx>, InterpErrorKind<'tcx>>;
|
||||
|
||||
#[inline]
|
||||
fn layout_tcx_at_span(&self) -> Span {
|
||||
@ -82,20 +82,25 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> InterpError<'tcx> {
|
||||
fn handle_layout_err(
|
||||
&self,
|
||||
err: LayoutError<'tcx>,
|
||||
_: Span,
|
||||
_: Ty<'tcx>,
|
||||
) -> InterpErrorKind<'tcx> {
|
||||
err_inval!(Layout(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
|
||||
type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpError<'tcx>>;
|
||||
type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpErrorKind<'tcx>>;
|
||||
|
||||
fn handle_fn_abi_err(
|
||||
&self,
|
||||
err: FnAbiError<'tcx>,
|
||||
_span: Span,
|
||||
_fn_abi_request: FnAbiRequest<'tcx>,
|
||||
) -> InterpError<'tcx> {
|
||||
) -> InterpErrorKind<'tcx> {
|
||||
match err {
|
||||
FnAbiError::Layout(err) => err_inval!(Layout(err)),
|
||||
FnAbiError::AdjustForForeignAbi(err) => {
|
||||
|
@ -324,13 +324,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
dist.checked_neg().unwrap(), // i64::MIN is impossible as no allocation can be that large
|
||||
CheckInAllocMsg::OffsetFromTest,
|
||||
)
|
||||
.map_err(|_| {
|
||||
.map_err_kind(|_| {
|
||||
// Make the error more specific.
|
||||
err_ub_custom!(
|
||||
fluent::const_eval_offset_from_different_allocations,
|
||||
name = intrinsic_name,
|
||||
)
|
||||
.into()
|
||||
})?;
|
||||
|
||||
// Perform division by size to compute return value.
|
||||
|
@ -17,8 +17,8 @@ use rustc_hir as hir;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::interpret::ValidationErrorKind::{self, *};
|
||||
use rustc_middle::mir::interpret::{
|
||||
ExpectedKind, InterpError, InterpErrorInfo, InvalidMetaKind, Misalignment, PointerKind,
|
||||
Provenance, UnsupportedOpInfo, ValidationErrorInfo, alloc_range, interp_ok,
|
||||
ExpectedKind, InterpErrorKind, InvalidMetaKind, Misalignment, PointerKind, Provenance,
|
||||
UnsupportedOpInfo, ValidationErrorInfo, alloc_range, interp_ok,
|
||||
};
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
@ -37,8 +37,8 @@ use super::{
|
||||
|
||||
// for the validation errors
|
||||
#[rustfmt::skip]
|
||||
use super::InterpError::UndefinedBehavior as Ub;
|
||||
use super::InterpError::Unsupported as Unsup;
|
||||
use super::InterpErrorKind::UndefinedBehavior as Ub;
|
||||
use super::InterpErrorKind::Unsupported as Unsup;
|
||||
use super::UndefinedBehaviorInfo::*;
|
||||
use super::UnsupportedOpInfo::*;
|
||||
|
||||
@ -97,20 +97,19 @@ macro_rules! try_validation {
|
||||
($e:expr, $where:expr,
|
||||
$( $( $p:pat_param )|+ => $kind: expr ),+ $(,)?
|
||||
) => {{
|
||||
$e.map_err(|e| {
|
||||
$e.map_err_kind(|e| {
|
||||
// We catch the error and turn it into a validation failure. We are okay with
|
||||
// allocation here as this can only slow down builds that fail anyway.
|
||||
let (kind, backtrace) = e.into_parts();
|
||||
match kind {
|
||||
match e {
|
||||
$(
|
||||
$($p)|+ => {
|
||||
err_validation_failure!(
|
||||
$where,
|
||||
$kind
|
||||
).into()
|
||||
)
|
||||
}
|
||||
),+,
|
||||
_ => InterpErrorInfo::from_parts(kind, backtrace),
|
||||
e => e,
|
||||
}
|
||||
})?
|
||||
}};
|
||||
@ -1230,11 +1229,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
|
||||
// No need for an alignment check here, this is not an actual memory access.
|
||||
let alloc = self.ecx.get_ptr_alloc(mplace.ptr(), size)?.expect("we already excluded size 0");
|
||||
|
||||
alloc.get_bytes_strip_provenance().map_err(|err| {
|
||||
alloc.get_bytes_strip_provenance().map_err_kind(|kind| {
|
||||
// Some error happened, try to provide a more detailed description.
|
||||
// For some errors we might be able to provide extra information.
|
||||
// (This custom logic does not fit the `try_validation!` macro.)
|
||||
let (kind, backtrace) = err.into_parts();
|
||||
match kind {
|
||||
Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => {
|
||||
// Some byte was uninitialized, determine which
|
||||
@ -1247,14 +1245,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
|
||||
self.path.push(PathElem::ArrayElem(i));
|
||||
|
||||
if matches!(kind, Ub(InvalidUninitBytes(_))) {
|
||||
err_validation_failure!(self.path, Uninit { expected }).into()
|
||||
err_validation_failure!(self.path, Uninit { expected })
|
||||
} else {
|
||||
err_validation_failure!(self.path, PointerAsInt { expected }).into()
|
||||
err_validation_failure!(self.path, PointerAsInt { expected })
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate upwards (that will also check for unexpected errors).
|
||||
_ => return InterpErrorInfo::from_parts(kind, backtrace),
|
||||
err => err,
|
||||
}
|
||||
})?;
|
||||
|
||||
@ -1368,12 +1366,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
v.reset_padding(val)?;
|
||||
interp_ok(())
|
||||
})
|
||||
.map_err(|err| {
|
||||
.map_err_info(|err| {
|
||||
if !matches!(
|
||||
err.kind(),
|
||||
err_ub!(ValidationError { .. })
|
||||
| InterpError::InvalidProgram(_)
|
||||
| InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField)
|
||||
| InterpErrorKind::InvalidProgram(_)
|
||||
| InterpErrorKind::Unsupported(UnsupportedOpInfo::ExternTypeField)
|
||||
) {
|
||||
bug!(
|
||||
"Unexpected error during validation: {}",
|
||||
|
@ -10,7 +10,6 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(unqualified_local_imports)]
|
||||
|
@ -13,7 +13,7 @@ ena = "0.14.3"
|
||||
indexmap = { version = "2.4.0" }
|
||||
jobserver_crate = { version = "0.1.28", package = "jobserver" }
|
||||
measureme = "11"
|
||||
rustc-hash = "1.1.0"
|
||||
rustc-hash = "2.0.0"
|
||||
rustc-rayon = { version = "0.5.0", optional = true }
|
||||
rustc-stable-hash = { version = "0.1.0", features = ["nightly"] }
|
||||
rustc_arena = { path = "../rustc_arena" }
|
||||
|
@ -33,7 +33,6 @@
|
||||
#![feature(ptr_alignment_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(test)]
|
||||
#![feature(thread_id_value)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
@ -353,6 +353,9 @@ declare_features! (
|
||||
(accepted, repr_packed, "1.33.0", Some(33158)),
|
||||
/// Allows `#[repr(transparent)]` attribute on newtype structs.
|
||||
(accepted, repr_transparent, "1.28.0", Some(43036)),
|
||||
/// Allows enums like Result<T, E> to be used across FFI, if T's niche value can
|
||||
/// be used to describe E or vice-versa.
|
||||
(accepted, result_ffi_guarantees, "CURRENT_RUSTC_VERSION", Some(110503)),
|
||||
/// Allows return-position `impl Trait` in traits.
|
||||
(accepted, return_position_impl_trait_in_trait, "1.75.0", Some(91611)),
|
||||
/// Allows code like `let x: &'static u32 = &42` to work (RFC 1414).
|
||||
|
@ -580,9 +580,6 @@ declare_features! (
|
||||
(incomplete, repr128, "1.16.0", Some(56071)),
|
||||
/// Allows `repr(simd)` and importing the various simd intrinsics.
|
||||
(unstable, repr_simd, "1.4.0", Some(27731)),
|
||||
/// Allows enums like Result<T, E> to be used across FFI, if T's niche value can
|
||||
/// be used to describe E or vise-versa.
|
||||
(unstable, result_ffi_guarantees, "1.80.0", Some(110503)),
|
||||
/// Allows bounding the return type of AFIT/RPITIT.
|
||||
(unstable, return_type_notation, "1.70.0", Some(109417)),
|
||||
/// Allows `extern "rust-cold"`.
|
||||
@ -598,7 +595,7 @@ declare_features! (
|
||||
/// Allows attributes on expressions and non-item statements.
|
||||
(unstable, stmt_expr_attributes, "1.6.0", Some(15701)),
|
||||
/// Allows lints part of the strict provenance effort.
|
||||
(unstable, strict_provenance, "1.61.0", Some(95228)),
|
||||
(unstable, strict_provenance_lints, "1.61.0", Some(130351)),
|
||||
/// Allows string patterns to dereference values to match them.
|
||||
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
|
||||
/// Allows the use of `#[target_feature]` on safe functions.
|
||||
|
@ -8,6 +8,7 @@ use fluent_syntax::ast::{
|
||||
Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern, PatternElement,
|
||||
};
|
||||
use fluent_syntax::parser::ParserError;
|
||||
use proc_macro::tracked_path::path;
|
||||
use proc_macro::{Diagnostic, Level, Span};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
@ -99,8 +100,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
|
||||
|
||||
let crate_name = Ident::new(&crate_name, resource_str.span());
|
||||
|
||||
// As this macro also outputs an `include_str!` for this file, the macro will always be
|
||||
// re-executed when the file changes.
|
||||
path(absolute_ftl_path.to_str().unwrap());
|
||||
let resource_contents = match read_to_string(absolute_ftl_path) {
|
||||
Ok(resource_contents) => resource_contents,
|
||||
Err(e) => {
|
||||
|
@ -6,6 +6,7 @@
|
||||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_span)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(track_path)]
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
@ -356,12 +356,14 @@ hir_analysis_only_current_traits_arbitrary = only traits defined in the current
|
||||
|
||||
hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait
|
||||
|
||||
hir_analysis_only_current_traits_label = impl doesn't use only types from inside the current crate
|
||||
|
||||
hir_analysis_only_current_traits_name = this is not defined in the current crate because {$name} are always foreign
|
||||
|
||||
hir_analysis_only_current_traits_note = define and implement a trait or new type instead
|
||||
|
||||
hir_analysis_only_current_traits_note_more_info = for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
|
||||
|
||||
hir_analysis_only_current_traits_note_uncovered = impl doesn't have any local type before any uncovered type parameters
|
||||
|
||||
hir_analysis_only_current_traits_opaque = type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate
|
||||
|
||||
hir_analysis_only_current_traits_outside = only traits defined in the current crate can be implemented for types defined outside of the crate
|
||||
|
@ -9,7 +9,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::DefId;
|
||||
|
||||
use crate::hir_ty_lowering::OnlySelfBounds;
|
||||
use crate::hir_ty_lowering::PredicateFilter;
|
||||
|
||||
/// Collects together a list of type bounds. These lists of bounds occur in many places
|
||||
/// in Rust's syntax:
|
||||
@ -51,8 +51,8 @@ impl<'tcx> Bounds<'tcx> {
|
||||
bound_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
span: Span,
|
||||
polarity: ty::PredicatePolarity,
|
||||
constness: ty::BoundConstness,
|
||||
only_self_bounds: OnlySelfBounds,
|
||||
constness: Option<ty::BoundConstness>,
|
||||
predicate_filter: PredicateFilter,
|
||||
) {
|
||||
let clause = (
|
||||
bound_trait_ref
|
||||
@ -72,26 +72,36 @@ impl<'tcx> Bounds<'tcx> {
|
||||
// FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else.
|
||||
// Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated
|
||||
// type bounds.
|
||||
if !tcx.features().effects || only_self_bounds.0 {
|
||||
if !tcx.features().effects {
|
||||
return;
|
||||
}
|
||||
match predicate_filter {
|
||||
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
|
||||
return;
|
||||
}
|
||||
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||
// Ok.
|
||||
}
|
||||
}
|
||||
|
||||
// For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the
|
||||
// associated type of `<T as Tr>` and make sure that the effect is compatible.
|
||||
let compat_val = match (tcx.def_kind(defining_def_id), constness) {
|
||||
// FIXME(effects): revisit the correctness of this
|
||||
(_, ty::BoundConstness::Const) => tcx.consts.false_,
|
||||
(_, Some(ty::BoundConstness::Const)) => tcx.consts.false_,
|
||||
// body owners that can have trait bounds
|
||||
(DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => {
|
||||
tcx.expected_host_effect_param_for_body(defining_def_id)
|
||||
}
|
||||
(
|
||||
DefKind::Const | DefKind::Fn | DefKind::AssocFn,
|
||||
Some(ty::BoundConstness::ConstIfConst),
|
||||
) => tcx.expected_host_effect_param_for_body(defining_def_id),
|
||||
|
||||
(_, ty::BoundConstness::NotConst) => {
|
||||
(_, None) => {
|
||||
if !tcx.is_const_trait(bound_trait_ref.def_id()) {
|
||||
return;
|
||||
}
|
||||
tcx.consts.true_
|
||||
}
|
||||
(DefKind::Trait, ty::BoundConstness::ConstIfConst) => {
|
||||
(DefKind::Trait, Some(ty::BoundConstness::ConstIfConst)) => {
|
||||
// we are in a trait, where `bound_trait_ref` could be:
|
||||
// (1) a super trait `trait Foo: ~const Bar`.
|
||||
// - This generates `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>`
|
||||
@ -129,7 +139,7 @@ impl<'tcx> Bounds<'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
(DefKind::Impl { of_trait: true }, ty::BoundConstness::ConstIfConst) => {
|
||||
(DefKind::Impl { of_trait: true }, Some(ty::BoundConstness::ConstIfConst)) => {
|
||||
// this is a where clause on an impl header.
|
||||
// push `<T as Tr>::Effects` into the set for the `Min` bound.
|
||||
let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
|
||||
@ -163,12 +173,12 @@ impl<'tcx> Bounds<'tcx> {
|
||||
//
|
||||
// FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor
|
||||
// that uses a `Bar` that implements `Trait` with `Maybe` effects.
|
||||
(DefKind::AssocTy, ty::BoundConstness::ConstIfConst) => {
|
||||
(DefKind::AssocTy, Some(ty::BoundConstness::ConstIfConst)) => {
|
||||
// FIXME(effects): implement this
|
||||
return;
|
||||
}
|
||||
// probably illegal in this position.
|
||||
(_, ty::BoundConstness::ConstIfConst) => {
|
||||
(_, Some(ty::BoundConstness::ConstIfConst)) => {
|
||||
tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered");
|
||||
return;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ use rustc_middle::ty::{
|
||||
AdtDef, GenericArgKind, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt,
|
||||
};
|
||||
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
|
||||
use rustc_session::lint::builtin::UNINHABITED_STATIC;
|
||||
use rustc_target::abi::FieldIdx;
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective;
|
||||
@ -36,36 +36,25 @@ use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_i
|
||||
use super::*;
|
||||
use crate::check::intrinsicck::InlineAsmCtxt;
|
||||
|
||||
pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
|
||||
match tcx.sess.target.is_abi_supported(abi) {
|
||||
Some(true) => (),
|
||||
Some(false) => {
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
span,
|
||||
E0570,
|
||||
"`{abi}` is not a supported ABI for the current target",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
None => {
|
||||
tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
|
||||
lint.primary_message("use of calling convention not supported on this target");
|
||||
});
|
||||
}
|
||||
pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) {
|
||||
if !tcx.sess.target.is_abi_supported(abi) {
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
span,
|
||||
E0570,
|
||||
"`{abi}` is not a supported ABI for the current target",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
|
||||
match tcx.sess.target.is_abi_supported(abi) {
|
||||
Some(true) => (),
|
||||
Some(false) | None => {
|
||||
tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
|
||||
lint.primary_message(format!(
|
||||
"the calling convention {abi} is not supported on this target"
|
||||
));
|
||||
});
|
||||
}
|
||||
if !tcx.sess.target.is_abi_supported(abi) {
|
||||
tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
|
||||
lint.primary_message(format!(
|
||||
"the calling convention {abi} is not supported on this target"
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -705,7 +694,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let hir::ItemKind::ForeignMod { abi, items } = it.kind else {
|
||||
return;
|
||||
};
|
||||
check_abi(tcx, it.hir_id(), it.span, abi);
|
||||
check_abi(tcx, it.span, abi);
|
||||
|
||||
match abi {
|
||||
Abi::RustIntrinsic => {
|
||||
@ -1037,7 +1026,11 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(len) = len_const.try_eval_target_usize(tcx, tcx.param_env(def.did())) {
|
||||
// FIXME(repr_simd): This check is nice, but perhaps unnecessary due to the fact
|
||||
// we do not expect users to implement their own `repr(simd)` types. If they could,
|
||||
// this check is easily side-steppable by hiding the const behind normalization.
|
||||
// The consequence is that the error is, in general, only observable post-mono.
|
||||
if let Some(len) = len_const.try_to_target_usize(tcx) {
|
||||
if len == 0 {
|
||||
struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
|
||||
return;
|
||||
|
@ -76,9 +76,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
|
||||
let (size, ty) = match elem_ty.kind() {
|
||||
ty::Array(ty, len) => {
|
||||
if let Some(len) =
|
||||
len.try_eval_target_usize(self.tcx, self.tcx.param_env(adt.did()))
|
||||
{
|
||||
if let Some(len) = len.try_to_target_usize(self.tcx) {
|
||||
(len, *ty)
|
||||
} else {
|
||||
return None;
|
||||
|
@ -13,6 +13,7 @@ use tracing::{debug, instrument};
|
||||
|
||||
use super::ItemCtxt;
|
||||
use super::predicates_of::assert_only_contains_predicates_from;
|
||||
use crate::bounds::Bounds;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter};
|
||||
|
||||
/// For associated types we include both bounds written on the type
|
||||
@ -36,7 +37,8 @@ fn associated_type_bounds<'tcx>(
|
||||
);
|
||||
|
||||
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
|
||||
let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter);
|
||||
let mut bounds = Bounds::default();
|
||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||
// Associated types are implicitly sized unless a `?Sized` bound is found
|
||||
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
|
||||
|
||||
@ -303,7 +305,8 @@ fn opaque_type_bounds<'tcx>(
|
||||
) -> &'tcx [(ty::Clause<'tcx>, Span)] {
|
||||
ty::print::with_reduced_queries!({
|
||||
let icx = ItemCtxt::new(tcx, opaque_def_id);
|
||||
let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter);
|
||||
let mut bounds = Bounds::default();
|
||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||
// Opaque types are implicitly sized unless a `?Sized` bound is found
|
||||
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
|
||||
debug!(?bounds);
|
||||
|
@ -16,7 +16,7 @@ use crate::bounds::Bounds;
|
||||
use crate::collect::ItemCtxt;
|
||||
use crate::constrained_generic_params as cgp;
|
||||
use crate::delegation::inherit_predicates_for_delegation_item;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason};
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason};
|
||||
|
||||
/// Returns a list of all type predicates (explicit and implicit) for the definition with
|
||||
/// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus
|
||||
@ -181,9 +181,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
// on a trait we must also consider the bounds that follow the trait's name,
|
||||
// like `trait Foo: A + B + C`.
|
||||
if let Some(self_bounds) = is_trait {
|
||||
let bounds = icx.lowerer().lower_mono_bounds(
|
||||
let mut bounds = Bounds::default();
|
||||
icx.lowerer().lower_bounds(
|
||||
tcx.types.self_param,
|
||||
self_bounds,
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::All,
|
||||
);
|
||||
predicates.extend(bounds.clauses(tcx));
|
||||
@ -265,12 +268,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
}
|
||||
|
||||
let mut bounds = Bounds::default();
|
||||
icx.lowerer().lower_poly_bounds(
|
||||
icx.lowerer().lower_bounds(
|
||||
ty,
|
||||
bound_pred.bounds.iter(),
|
||||
bound_pred.bounds,
|
||||
&mut bounds,
|
||||
bound_vars,
|
||||
OnlySelfBounds(false),
|
||||
PredicateFilter::All,
|
||||
);
|
||||
predicates.extend(bounds.clauses(tcx));
|
||||
effects_min_tys.extend(bounds.effects_min_tys());
|
||||
@ -626,7 +629,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
|
||||
bug!("trait_def_id {trait_def_id:?} is not an item");
|
||||
};
|
||||
|
||||
let (generics, bounds) = match item.kind {
|
||||
let (generics, superbounds) = match item.kind {
|
||||
hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits),
|
||||
hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits),
|
||||
_ => span_bug!(item.span, "super_predicates invoked on non-trait"),
|
||||
@ -635,7 +638,8 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
|
||||
let icx = ItemCtxt::new(tcx, trait_def_id);
|
||||
|
||||
let self_param_ty = tcx.types.self_param;
|
||||
let superbounds = icx.lowerer().lower_mono_bounds(self_param_ty, bounds, filter);
|
||||
let mut bounds = Bounds::default();
|
||||
icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter);
|
||||
|
||||
let where_bounds_that_match = icx.probe_ty_param_bounds_in_generics(
|
||||
generics,
|
||||
@ -646,7 +650,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
|
||||
|
||||
// Combine the two lists to form the complete set of superbounds:
|
||||
let implied_bounds =
|
||||
&*tcx.arena.alloc_from_iter(superbounds.clauses(tcx).chain(where_bounds_that_match));
|
||||
&*tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(where_bounds_that_match));
|
||||
debug!(?implied_bounds);
|
||||
|
||||
// Now require that immediate supertraits are lowered, which will, in
|
||||
@ -825,20 +829,6 @@ impl<'tcx> ItemCtxt<'tcx> {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we
|
||||
// want to only consider predicates with `Self: ...`, but we don't want
|
||||
// `OnlySelfBounds(true)` since we want to collect the nested associated
|
||||
// type bound as well.
|
||||
let (only_self_bounds, assoc_name) = match filter {
|
||||
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||
(OnlySelfBounds(false), None)
|
||||
}
|
||||
PredicateFilter::SelfOnly => (OnlySelfBounds(true), None),
|
||||
PredicateFilter::SelfThatDefines(assoc_name) => {
|
||||
(OnlySelfBounds(true), Some(assoc_name))
|
||||
}
|
||||
};
|
||||
|
||||
let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
|
||||
ty
|
||||
} else if matches!(filter, PredicateFilter::All) {
|
||||
@ -848,33 +838,15 @@ impl<'tcx> ItemCtxt<'tcx> {
|
||||
};
|
||||
|
||||
let bound_vars = self.tcx.late_bound_vars(predicate.hir_id);
|
||||
self.lowerer().lower_poly_bounds(
|
||||
self.lowerer().lower_bounds(
|
||||
bound_ty,
|
||||
predicate.bounds.iter().filter(|bound| {
|
||||
assoc_name
|
||||
.map_or(true, |assoc_name| self.bound_defines_assoc_item(bound, assoc_name))
|
||||
}),
|
||||
predicate.bounds,
|
||||
&mut bounds,
|
||||
bound_vars,
|
||||
only_self_bounds,
|
||||
filter,
|
||||
);
|
||||
}
|
||||
|
||||
bounds.clauses(self.tcx).collect()
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
|
||||
match b {
|
||||
hir::GenericBound::Trait(poly_trait_ref) => {
|
||||
let trait_ref = &poly_trait_ref.trait_ref;
|
||||
if let Some(trait_did) = trait_ref.trait_def_id() {
|
||||
self.tcx.trait_may_define_assoc_item(trait_did, assoc_name)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1434,24 +1434,27 @@ pub(crate) enum OnlyCurrentTraits {
|
||||
#[diag(hir_analysis_only_current_traits_outside, code = E0117)]
|
||||
Outside {
|
||||
#[primary_span]
|
||||
#[label(hir_analysis_only_current_traits_label)]
|
||||
span: Span,
|
||||
#[note(hir_analysis_only_current_traits_note_uncovered)]
|
||||
#[note(hir_analysis_only_current_traits_note_more_info)]
|
||||
#[note(hir_analysis_only_current_traits_note)]
|
||||
note: (),
|
||||
},
|
||||
#[diag(hir_analysis_only_current_traits_primitive, code = E0117)]
|
||||
Primitive {
|
||||
#[primary_span]
|
||||
#[label(hir_analysis_only_current_traits_label)]
|
||||
span: Span,
|
||||
#[note(hir_analysis_only_current_traits_note_uncovered)]
|
||||
#[note(hir_analysis_only_current_traits_note_more_info)]
|
||||
#[note(hir_analysis_only_current_traits_note)]
|
||||
note: (),
|
||||
},
|
||||
#[diag(hir_analysis_only_current_traits_arbitrary, code = E0117)]
|
||||
Arbitrary {
|
||||
#[primary_span]
|
||||
#[label(hir_analysis_only_current_traits_label)]
|
||||
span: Span,
|
||||
#[note(hir_analysis_only_current_traits_note_uncovered)]
|
||||
#[note(hir_analysis_only_current_traits_note_more_info)]
|
||||
#[note(hir_analysis_only_current_traits_note)]
|
||||
note: (),
|
||||
},
|
||||
|
@ -19,9 +19,7 @@ use tracing::{debug, instrument};
|
||||
use super::errors::GenericsArgsErrExtend;
|
||||
use crate::bounds::Bounds;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{
|
||||
AssocItemQSelf, HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason,
|
||||
};
|
||||
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer, PredicateFilter, RegionInferReason};
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// Add a `Sized` bound to the `bounds` if appropriate.
|
||||
@ -144,31 +142,44 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// There is an implied binder around `param_ty` and `hir_bounds`.
|
||||
/// See `lower_poly_trait_ref` for more details.
|
||||
#[instrument(level = "debug", skip(self, hir_bounds, bounds))]
|
||||
pub(crate) fn lower_poly_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'tcx>>>(
|
||||
pub(crate) fn lower_bounds<'hir, I: IntoIterator<Item = &'hir hir::GenericBound<'tcx>>>(
|
||||
&self,
|
||||
param_ty: Ty<'tcx>,
|
||||
hir_bounds: I,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
|
||||
only_self_bounds: OnlySelfBounds,
|
||||
predicate_filter: PredicateFilter,
|
||||
) where
|
||||
'tcx: 'hir,
|
||||
{
|
||||
for hir_bound in hir_bounds {
|
||||
// In order to avoid cycles, when we're lowering `SelfThatDefines`,
|
||||
// we skip over any traits that don't define the given associated type.
|
||||
|
||||
if let PredicateFilter::SelfThatDefines(assoc_name) = predicate_filter {
|
||||
if let Some(trait_ref) = hir_bound.trait_ref()
|
||||
&& let Some(trait_did) = trait_ref.trait_def_id()
|
||||
&& self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
|
||||
{
|
||||
// Okay
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
match hir_bound {
|
||||
hir::GenericBound::Trait(poly_trait_ref) => {
|
||||
let (constness, polarity) = match poly_trait_ref.modifiers {
|
||||
hir::TraitBoundModifier::Const => {
|
||||
(ty::BoundConstness::Const, ty::PredicatePolarity::Positive)
|
||||
}
|
||||
hir::TraitBoundModifier::MaybeConst => {
|
||||
(ty::BoundConstness::ConstIfConst, ty::PredicatePolarity::Positive)
|
||||
}
|
||||
hir::TraitBoundModifier::None => {
|
||||
(ty::BoundConstness::NotConst, ty::PredicatePolarity::Positive)
|
||||
(Some(ty::BoundConstness::Const), ty::PredicatePolarity::Positive)
|
||||
}
|
||||
hir::TraitBoundModifier::MaybeConst => (
|
||||
Some(ty::BoundConstness::ConstIfConst),
|
||||
ty::PredicatePolarity::Positive,
|
||||
),
|
||||
hir::TraitBoundModifier::None => (None, ty::PredicatePolarity::Positive),
|
||||
hir::TraitBoundModifier::Negative => {
|
||||
(ty::BoundConstness::NotConst, ty::PredicatePolarity::Negative)
|
||||
(None, ty::PredicatePolarity::Negative)
|
||||
}
|
||||
hir::TraitBoundModifier::Maybe => continue,
|
||||
};
|
||||
@ -179,7 +190,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
polarity,
|
||||
param_ty,
|
||||
bounds,
|
||||
only_self_bounds,
|
||||
predicate_filter,
|
||||
);
|
||||
}
|
||||
hir::GenericBound::Outlives(lifetime) => {
|
||||
@ -200,56 +211,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower HIR bounds into `bounds` given the self type `param_ty` and *no* overarching late-bound vars.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// fn foo<T: Bar + Baz>() { }
|
||||
/// // ^ ^^^^^^^^^ hir_bounds
|
||||
/// // param_ty
|
||||
/// ```
|
||||
pub(crate) fn lower_mono_bounds(
|
||||
&self,
|
||||
param_ty: Ty<'tcx>,
|
||||
hir_bounds: &[hir::GenericBound<'tcx>],
|
||||
filter: PredicateFilter,
|
||||
) -> Bounds<'tcx> {
|
||||
let mut bounds = Bounds::default();
|
||||
|
||||
let only_self_bounds = match filter {
|
||||
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||
OnlySelfBounds(false)
|
||||
}
|
||||
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => OnlySelfBounds(true),
|
||||
};
|
||||
|
||||
self.lower_poly_bounds(
|
||||
param_ty,
|
||||
hir_bounds.iter().filter(|bound| match filter {
|
||||
PredicateFilter::All
|
||||
| PredicateFilter::SelfOnly
|
||||
| PredicateFilter::SelfAndAssociatedTypeBounds => true,
|
||||
PredicateFilter::SelfThatDefines(assoc_name) => {
|
||||
if let Some(trait_ref) = bound.trait_ref()
|
||||
&& let Some(trait_did) = trait_ref.trait_def_id()
|
||||
&& self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}),
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
only_self_bounds,
|
||||
);
|
||||
debug!(?bounds);
|
||||
|
||||
bounds
|
||||
}
|
||||
|
||||
/// Lower an associated item constraint from the HIR into `bounds`.
|
||||
///
|
||||
/// ### A Note on Binders
|
||||
@ -267,7 +228,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
duplicates: &mut FxIndexMap<DefId, Span>,
|
||||
path_span: Span,
|
||||
only_self_bounds: OnlySelfBounds,
|
||||
predicate_filter: PredicateFilter,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
@ -444,21 +405,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
// Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator<Item: Debug>`
|
||||
// to a bound involving a projection: `<T as Iterator>::Item: Debug`.
|
||||
hir::AssocItemConstraintKind::Bound { bounds: hir_bounds } => {
|
||||
// NOTE: If `only_self_bounds` is true, do NOT expand this associated type bound into
|
||||
// a trait predicate, since we only want to add predicates for the `Self` type.
|
||||
if !only_self_bounds.0 {
|
||||
let projection_ty = projection_term
|
||||
.map_bound(|projection_term| projection_term.expect_ty(self.tcx()));
|
||||
// Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
|
||||
// parameter to have a skipped binder.
|
||||
let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
|
||||
self.lower_poly_bounds(
|
||||
param_ty,
|
||||
hir_bounds.iter(),
|
||||
bounds,
|
||||
projection_ty.bound_vars(),
|
||||
only_self_bounds,
|
||||
);
|
||||
match predicate_filter {
|
||||
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {}
|
||||
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||
let projection_ty = projection_term
|
||||
.map_bound(|projection_term| projection_term.expect_ty(self.tcx()));
|
||||
// Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
|
||||
// parameter to have a skipped binder.
|
||||
let param_ty =
|
||||
Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
|
||||
self.lower_bounds(
|
||||
param_ty,
|
||||
hir_bounds,
|
||||
bounds,
|
||||
projection_ty.bound_vars(),
|
||||
predicate_filter,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -516,7 +479,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
self_ty,
|
||||
trait_segment,
|
||||
false,
|
||||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
|
||||
// SUBTLE: As noted at the end of `try_append_return_type_notation_params`
|
||||
|
@ -20,7 +20,7 @@ use tracing::{debug, instrument};
|
||||
use super::HirTyLowerer;
|
||||
use crate::bounds::Bounds;
|
||||
use crate::hir_ty_lowering::{
|
||||
GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason,
|
||||
GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason,
|
||||
};
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
@ -51,13 +51,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
} = self.lower_poly_trait_ref(
|
||||
&trait_bound.trait_ref,
|
||||
trait_bound.span,
|
||||
ty::BoundConstness::NotConst,
|
||||
None,
|
||||
ty::PredicatePolarity::Positive,
|
||||
dummy_self,
|
||||
&mut bounds,
|
||||
// True so we don't populate `bounds` with associated type bounds, even
|
||||
// though they're disallowed from object types.
|
||||
OnlySelfBounds(true),
|
||||
PredicateFilter::SelfOnly,
|
||||
) {
|
||||
potential_assoc_types.extend(cur_potential_assoc_types);
|
||||
}
|
||||
|
@ -64,9 +64,6 @@ use crate::require_c_abi_if_c_variadic;
|
||||
#[derive(Debug)]
|
||||
pub struct GenericPathSegment(pub DefId, pub usize);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct OnlySelfBounds(pub bool);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum PredicateFilter {
|
||||
/// All predicates may be implied by the trait.
|
||||
@ -76,7 +73,8 @@ pub enum PredicateFilter {
|
||||
SelfOnly,
|
||||
|
||||
/// Only traits that reference `Self: ..` and define an associated type
|
||||
/// with the given ident are implied by the trait.
|
||||
/// with the given ident are implied by the trait. This mode exists to
|
||||
/// side-step query cycles when lowering associated types.
|
||||
SelfThatDefines(Ident),
|
||||
|
||||
/// Only traits that reference `Self: ..` and their associated type bounds.
|
||||
@ -336,14 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
def_id: DefId,
|
||||
item_segment: &hir::PathSegment<'tcx>,
|
||||
) -> GenericArgsRef<'tcx> {
|
||||
let (args, _) = self.lower_generic_args_of_path(
|
||||
span,
|
||||
def_id,
|
||||
&[],
|
||||
item_segment,
|
||||
None,
|
||||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
let (args, _) = self.lower_generic_args_of_path(span, def_id, &[], item_segment, None);
|
||||
if let Some(c) = item_segment.args().constraints.first() {
|
||||
prohibit_assoc_item_constraint(self, c, Some((def_id, item_segment, span)));
|
||||
}
|
||||
@ -392,7 +383,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
parent_args: &[ty::GenericArg<'tcx>],
|
||||
segment: &hir::PathSegment<'tcx>,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
constness: ty::BoundConstness,
|
||||
) -> (GenericArgsRef<'tcx>, GenericArgCountResult) {
|
||||
// If the type is parameterized by this region, then replace this
|
||||
// region with the current anon region binding (in other words,
|
||||
@ -415,7 +405,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
assert!(self_ty.is_none());
|
||||
}
|
||||
|
||||
let mut arg_count = check_generic_arg_count(
|
||||
let arg_count = check_generic_arg_count(
|
||||
self,
|
||||
def_id,
|
||||
segment,
|
||||
@ -573,16 +563,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
}
|
||||
}
|
||||
if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
|
||||
&& generics.has_self
|
||||
&& !tcx.is_const_trait(def_id)
|
||||
{
|
||||
let reported = self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
|
||||
span,
|
||||
modifier: constness.as_str(),
|
||||
});
|
||||
arg_count.correct = Err(GenericArgCountMismatch { reported, invalid_args: vec![] });
|
||||
}
|
||||
|
||||
let mut args_ctx = GenericArgsCtxt {
|
||||
lowerer: self,
|
||||
@ -614,14 +594,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
parent_args: GenericArgsRef<'tcx>,
|
||||
) -> GenericArgsRef<'tcx> {
|
||||
debug!(?span, ?item_def_id, ?item_segment);
|
||||
let (args, _) = self.lower_generic_args_of_path(
|
||||
span,
|
||||
item_def_id,
|
||||
parent_args,
|
||||
item_segment,
|
||||
None,
|
||||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
let (args, _) =
|
||||
self.lower_generic_args_of_path(span, item_def_id, parent_args, item_segment, None);
|
||||
if let Some(c) = item_segment.args().constraints.first() {
|
||||
prohibit_assoc_item_constraint(self, c, Some((item_def_id, item_segment, span)));
|
||||
}
|
||||
@ -647,7 +621,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
self_ty,
|
||||
trait_ref.path.segments.last().unwrap(),
|
||||
true,
|
||||
ty::BoundConstness::NotConst,
|
||||
)
|
||||
}
|
||||
|
||||
@ -679,11 +652,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
&self,
|
||||
trait_ref: &hir::TraitRef<'tcx>,
|
||||
span: Span,
|
||||
constness: ty::BoundConstness,
|
||||
constness: Option<ty::BoundConstness>,
|
||||
polarity: ty::PredicatePolarity,
|
||||
self_ty: Ty<'tcx>,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
only_self_bounds: OnlySelfBounds,
|
||||
predicate_filter: PredicateFilter,
|
||||
) -> GenericArgCountResult {
|
||||
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
|
||||
let trait_segment = trait_ref.path.segments.last().unwrap();
|
||||
@ -700,9 +673,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
&[],
|
||||
trait_segment,
|
||||
Some(self_ty),
|
||||
constness,
|
||||
);
|
||||
|
||||
if let Some(constness) = constness
|
||||
&& !self.tcx().is_const_trait(trait_def_id)
|
||||
{
|
||||
self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
|
||||
span: trait_ref.path.span,
|
||||
modifier: constness.as_str(),
|
||||
});
|
||||
}
|
||||
|
||||
let tcx = self.tcx();
|
||||
let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
|
||||
debug!(?bound_vars);
|
||||
@ -720,7 +701,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
span,
|
||||
polarity,
|
||||
constness,
|
||||
only_self_bounds,
|
||||
predicate_filter,
|
||||
);
|
||||
|
||||
let mut dup_constraints = FxIndexMap::default();
|
||||
@ -744,7 +725,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
bounds,
|
||||
&mut dup_constraints,
|
||||
constraint.span,
|
||||
only_self_bounds,
|
||||
predicate_filter,
|
||||
);
|
||||
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
|
||||
}
|
||||
@ -762,19 +743,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_segment: &hir::PathSegment<'tcx>,
|
||||
is_impl: bool,
|
||||
// FIXME(effects): Move all host param things in HIR ty lowering to AST lowering.
|
||||
constness: ty::BoundConstness,
|
||||
) -> ty::TraitRef<'tcx> {
|
||||
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
|
||||
|
||||
let (generic_args, _) = self.lower_generic_args_of_path(
|
||||
span,
|
||||
trait_def_id,
|
||||
&[],
|
||||
trait_segment,
|
||||
Some(self_ty),
|
||||
constness,
|
||||
);
|
||||
let (generic_args, _) =
|
||||
self.lower_generic_args_of_path(span, trait_def_id, &[], trait_segment, Some(self_ty));
|
||||
if let Some(c) = trait_segment.args().constraints.first() {
|
||||
prohibit_assoc_item_constraint(self, c, Some((trait_def_id, trait_segment, span)));
|
||||
}
|
||||
@ -1542,7 +1515,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
item_def_id: DefId,
|
||||
trait_segment: &hir::PathSegment<'tcx>,
|
||||
item_segment: &hir::PathSegment<'tcx>,
|
||||
constness: ty::BoundConstness,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
@ -1555,7 +1527,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
debug!(?self_ty);
|
||||
|
||||
let trait_ref =
|
||||
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false, constness);
|
||||
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
|
||||
debug!(?trait_ref);
|
||||
|
||||
let item_args =
|
||||
@ -1918,7 +1890,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
def_id,
|
||||
&path.segments[path.segments.len() - 2],
|
||||
path.segments.last().unwrap(),
|
||||
ty::BoundConstness::NotConst,
|
||||
)
|
||||
}
|
||||
Res::PrimTy(prim_ty) => {
|
||||
@ -2151,7 +2122,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
&[],
|
||||
&hir::PathSegment::invalid(),
|
||||
None,
|
||||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
tcx.at(span).type_of(def_id).instantiate(tcx, args)
|
||||
}
|
||||
|
@ -537,40 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
//
|
||||
// This check is here because there is currently no way to express a trait bound for `FnDef` types only.
|
||||
if let ty::FnDef(def_id, _args) = *arg_ty.kind() {
|
||||
let fn_once_def_id =
|
||||
self.tcx.require_lang_item(hir::LangItem::FnOnce, Some(span));
|
||||
let fn_once_output_def_id =
|
||||
self.tcx.require_lang_item(hir::LangItem::FnOnceOutput, Some(span));
|
||||
if self.tcx.has_host_param(fn_once_def_id) {
|
||||
let const_param: ty::GenericArg<'tcx> =
|
||||
([self.tcx.consts.false_, self.tcx.consts.true_])[idx].into();
|
||||
self.register_predicate(traits::Obligation::new(
|
||||
self.tcx,
|
||||
self.misc(span),
|
||||
self.param_env,
|
||||
ty::TraitRef::new(self.tcx, fn_once_def_id, [
|
||||
arg_ty.into(),
|
||||
fn_sig.inputs()[0].into(),
|
||||
const_param,
|
||||
]),
|
||||
));
|
||||
|
||||
self.register_predicate(traits::Obligation::new(
|
||||
self.tcx,
|
||||
self.misc(span),
|
||||
self.param_env,
|
||||
ty::ProjectionPredicate {
|
||||
projection_term: ty::AliasTerm::new(
|
||||
self.tcx,
|
||||
fn_once_output_def_id,
|
||||
[arg_ty.into(), fn_sig.inputs()[0].into(), const_param],
|
||||
),
|
||||
term: fn_sig.output().into(),
|
||||
},
|
||||
));
|
||||
|
||||
self.select_obligations_where_possible(|_| {});
|
||||
} else if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
|
||||
if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
|
||||
self.dcx().emit_err(errors::ConstSelectMustBeConst { span });
|
||||
}
|
||||
} else {
|
||||
|
@ -1320,84 +1320,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) -> Ty<'tcx> {
|
||||
let expected_ty = expected.coercion_target_type(self, expr.span);
|
||||
if expected_ty == self.tcx.types.bool {
|
||||
// The expected type is `bool` but this will result in `()` so we can reasonably
|
||||
// say that the user intended to write `lhs == rhs` instead of `lhs = rhs`.
|
||||
// The likely cause of this is `if foo = bar { .. }`.
|
||||
let actual_ty = self.tcx.types.unit;
|
||||
let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap_err();
|
||||
let lhs_ty = self.check_expr(lhs);
|
||||
let rhs_ty = self.check_expr(rhs);
|
||||
let refs_can_coerce = |lhs: Ty<'tcx>, rhs: Ty<'tcx>| {
|
||||
let lhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, lhs.peel_refs());
|
||||
let rhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rhs.peel_refs());
|
||||
self.may_coerce(rhs, lhs)
|
||||
};
|
||||
let (applicability, eq) = if self.may_coerce(rhs_ty, lhs_ty) {
|
||||
(Applicability::MachineApplicable, true)
|
||||
} else if refs_can_coerce(rhs_ty, lhs_ty) {
|
||||
// The lhs and rhs are likely missing some references in either side. Subsequent
|
||||
// suggestions will show up.
|
||||
(Applicability::MaybeIncorrect, true)
|
||||
} else if let ExprKind::Binary(
|
||||
Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
|
||||
_,
|
||||
rhs_expr,
|
||||
) = lhs.kind
|
||||
{
|
||||
// if x == 1 && y == 2 { .. }
|
||||
// +
|
||||
let actual_lhs_ty = self.check_expr(rhs_expr);
|
||||
(
|
||||
Applicability::MaybeIncorrect,
|
||||
self.may_coerce(rhs_ty, actual_lhs_ty)
|
||||
|| refs_can_coerce(rhs_ty, actual_lhs_ty),
|
||||
)
|
||||
} else if let ExprKind::Binary(
|
||||
Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
|
||||
lhs_expr,
|
||||
_,
|
||||
) = rhs.kind
|
||||
{
|
||||
// if x == 1 && y == 2 { .. }
|
||||
// +
|
||||
let actual_rhs_ty = self.check_expr(lhs_expr);
|
||||
(
|
||||
Applicability::MaybeIncorrect,
|
||||
self.may_coerce(actual_rhs_ty, lhs_ty)
|
||||
|| refs_can_coerce(actual_rhs_ty, lhs_ty),
|
||||
)
|
||||
} else {
|
||||
(Applicability::MaybeIncorrect, false)
|
||||
};
|
||||
if !lhs.is_syntactic_place_expr()
|
||||
&& lhs.is_approximately_pattern()
|
||||
&& !matches!(lhs.kind, hir::ExprKind::Lit(_))
|
||||
{
|
||||
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
|
||||
if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
|
||||
self.tcx.parent_hir_node(expr.hir_id)
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_lo(),
|
||||
"you might have meant to use pattern matching",
|
||||
"let ",
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
}
|
||||
if eq {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"you might have meant to compare for equality",
|
||||
'=',
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
||||
// If the assignment expression itself is ill-formed, don't
|
||||
// bother emitting another error
|
||||
let reported = err.emit_unless(lhs_ty.references_error() || rhs_ty.references_error());
|
||||
return Ty::new_error(self.tcx, reported);
|
||||
let guar = self.expr_assign_expected_bool_error(expr, lhs, rhs, span);
|
||||
return Ty::new_error(self.tcx, guar);
|
||||
}
|
||||
|
||||
let lhs_ty = self.check_expr_with_needs(lhs, Needs::MutPlace);
|
||||
@ -1450,6 +1374,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The expected type is `bool` but this will result in `()` so we can reasonably
|
||||
/// say that the user intended to write `lhs == rhs` instead of `lhs = rhs`.
|
||||
/// The likely cause of this is `if foo = bar { .. }`.
|
||||
fn expr_assign_expected_bool_error(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
lhs: &'tcx hir::Expr<'tcx>,
|
||||
rhs: &'tcx hir::Expr<'tcx>,
|
||||
span: Span,
|
||||
) -> ErrorGuaranteed {
|
||||
let actual_ty = self.tcx.types.unit;
|
||||
let expected_ty = self.tcx.types.bool;
|
||||
let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap_err();
|
||||
let lhs_ty = self.check_expr(lhs);
|
||||
let rhs_ty = self.check_expr(rhs);
|
||||
let refs_can_coerce = |lhs: Ty<'tcx>, rhs: Ty<'tcx>| {
|
||||
let lhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, lhs.peel_refs());
|
||||
let rhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rhs.peel_refs());
|
||||
self.may_coerce(rhs, lhs)
|
||||
};
|
||||
let (applicability, eq) = if self.may_coerce(rhs_ty, lhs_ty) {
|
||||
(Applicability::MachineApplicable, true)
|
||||
} else if refs_can_coerce(rhs_ty, lhs_ty) {
|
||||
// The lhs and rhs are likely missing some references in either side. Subsequent
|
||||
// suggestions will show up.
|
||||
(Applicability::MaybeIncorrect, true)
|
||||
} else if let ExprKind::Binary(
|
||||
Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
|
||||
_,
|
||||
rhs_expr,
|
||||
) = lhs.kind
|
||||
{
|
||||
// if x == 1 && y == 2 { .. }
|
||||
// +
|
||||
let actual_lhs = self.check_expr(rhs_expr);
|
||||
let may_eq = self.may_coerce(rhs_ty, actual_lhs) || refs_can_coerce(rhs_ty, actual_lhs);
|
||||
(Applicability::MaybeIncorrect, may_eq)
|
||||
} else if let ExprKind::Binary(
|
||||
Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
|
||||
lhs_expr,
|
||||
_,
|
||||
) = rhs.kind
|
||||
{
|
||||
// if x == 1 && y == 2 { .. }
|
||||
// +
|
||||
let actual_rhs = self.check_expr(lhs_expr);
|
||||
let may_eq = self.may_coerce(actual_rhs, lhs_ty) || refs_can_coerce(actual_rhs, lhs_ty);
|
||||
(Applicability::MaybeIncorrect, may_eq)
|
||||
} else {
|
||||
(Applicability::MaybeIncorrect, false)
|
||||
};
|
||||
|
||||
if !lhs.is_syntactic_place_expr()
|
||||
&& lhs.is_approximately_pattern()
|
||||
&& !matches!(lhs.kind, hir::ExprKind::Lit(_))
|
||||
{
|
||||
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
|
||||
if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
|
||||
self.tcx.parent_hir_node(expr.hir_id)
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_lo(),
|
||||
"you might have meant to use pattern matching",
|
||||
"let ",
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
}
|
||||
if eq {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"you might have meant to compare for equality",
|
||||
'=',
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
||||
// If the assignment expression itself is ill-formed, don't
|
||||
// bother emitting another error
|
||||
err.emit_unless(lhs_ty.references_error() || rhs_ty.references_error())
|
||||
}
|
||||
|
||||
pub(super) fn check_expr_let(
|
||||
&self,
|
||||
let_expr: &'tcx hir::LetExpr<'tcx>,
|
||||
|
@ -1487,7 +1487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
} else if self.tcx.features().generic_const_exprs {
|
||||
ct.normalize(self.tcx, self.param_env)
|
||||
ct.normalize_internal(self.tcx, self.param_env)
|
||||
} else {
|
||||
ct
|
||||
}
|
||||
|
@ -1097,6 +1097,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let mut only_extras_so_far = errors
|
||||
.peek()
|
||||
.is_some_and(|first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0));
|
||||
let mut prev_extra_idx = None;
|
||||
let mut suggestions = vec![];
|
||||
while let Some(error) = errors.next() {
|
||||
only_extras_so_far &= matches!(error, Error::Extra(_));
|
||||
@ -1165,11 +1166,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// fn f() {}
|
||||
// - f(0, 1,)
|
||||
// + f()
|
||||
if only_extras_so_far
|
||||
&& !errors
|
||||
.peek()
|
||||
.is_some_and(|next_error| matches!(next_error, Error::Extra(_)))
|
||||
{
|
||||
let trim_next_comma = match errors.peek() {
|
||||
Some(Error::Extra(provided_idx))
|
||||
if only_extras_so_far
|
||||
&& provided_idx.index() > arg_idx.index() + 1 =>
|
||||
// If the next Error::Extra ("next") doesn't next to current ("current"),
|
||||
// fn foo(_: (), _: u32) {}
|
||||
// - foo("current", (), 1u32, "next")
|
||||
// + foo((), 1u32)
|
||||
// If the previous error is not a `Error::Extra`, then do not trim the next comma
|
||||
// - foo((), "current", 42u32, "next")
|
||||
// + foo((), 42u32)
|
||||
{
|
||||
prev_extra_idx.map_or(true, |prev_extra_idx| {
|
||||
prev_extra_idx + 1 == arg_idx.index()
|
||||
})
|
||||
}
|
||||
// If no error left, we need to delete the next comma
|
||||
None if only_extras_so_far => true,
|
||||
// Not sure if other error type need to be handled as well
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if trim_next_comma {
|
||||
let next = provided_arg_tys
|
||||
.get(arg_idx + 1)
|
||||
.map(|&(_, sp)| sp)
|
||||
@ -1192,6 +1211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
SuggestionText::Remove(_) => SuggestionText::Remove(true),
|
||||
_ => SuggestionText::DidYouMean,
|
||||
};
|
||||
prev_extra_idx = Some(arg_idx.index())
|
||||
}
|
||||
}
|
||||
Error::Missing(expected_idx) => {
|
||||
|
@ -155,7 +155,7 @@ fn typeck_with_fallback<'tcx>(
|
||||
tcx.fn_sig(def_id).instantiate_identity()
|
||||
};
|
||||
|
||||
check_abi(tcx, id, span, fn_sig.abi());
|
||||
check_abi(tcx, span, fn_sig.abi());
|
||||
|
||||
// Compute the function signature from point of view of inside the fn.
|
||||
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
|
||||
@ -419,7 +419,7 @@ fn report_unexpected_variant_res(
|
||||
}
|
||||
}
|
||||
|
||||
err.multipart_suggestion_verbose(descr, suggestion, Applicability::MaybeIncorrect);
|
||||
err.multipart_suggestion_verbose(descr, suggestion, Applicability::HasPlaceholders);
|
||||
err
|
||||
}
|
||||
Res::Def(DefKind::Variant, _) if expr.is_none() => {
|
||||
|
@ -340,13 +340,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result<R, MethodError<'tcx>>,
|
||||
{
|
||||
let mut orig_values = OriginalQueryValues::default();
|
||||
let param_env_and_self_ty = self.canonicalize_query(
|
||||
let query_input = self.canonicalize_query(
|
||||
ParamEnvAnd { param_env: self.param_env, value: self_ty },
|
||||
&mut orig_values,
|
||||
);
|
||||
|
||||
let steps = match mode {
|
||||
Mode::MethodCall => self.tcx.method_autoderef_steps(param_env_and_self_ty),
|
||||
Mode::MethodCall => self.tcx.method_autoderef_steps(query_input),
|
||||
Mode::Path => self.probe(|_| {
|
||||
// Mode::Path - the deref steps is "trivial". This turns
|
||||
// our CanonicalQuery into a "trivial" QueryResponse. This
|
||||
@ -355,11 +355,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
let infcx = &self.infcx;
|
||||
let (ParamEnvAnd { param_env: _, value: self_ty }, canonical_inference_vars) =
|
||||
infcx.instantiate_canonical(span, ¶m_env_and_self_ty);
|
||||
debug!(
|
||||
"probe_op: Mode::Path, param_env_and_self_ty={:?} self_ty={:?}",
|
||||
param_env_and_self_ty, self_ty
|
||||
);
|
||||
infcx.instantiate_canonical(span, &query_input.canonical);
|
||||
debug!(?self_ty, ?query_input, "probe_op: Mode::Path");
|
||||
MethodAutoderefStepsResult {
|
||||
steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
|
||||
self_ty: self.make_query_response_ignoring_pending_obligations(
|
||||
|
@ -17,7 +17,8 @@ use tracing::debug;
|
||||
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::canonical::{
|
||||
Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
|
||||
Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind,
|
||||
OriginalQueryValues,
|
||||
};
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
@ -40,12 +41,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
&self,
|
||||
value: ty::ParamEnvAnd<'tcx, V>,
|
||||
query_state: &mut OriginalQueryValues<'tcx>,
|
||||
) -> Canonical<'tcx, ty::ParamEnvAnd<'tcx, V>>
|
||||
) -> CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, V>>
|
||||
where
|
||||
V: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let (param_env, value) = value.into_parts();
|
||||
let mut param_env = self.tcx.canonical_param_env_cache.get_or_insert(
|
||||
let param_env = self.tcx.canonical_param_env_cache.get_or_insert(
|
||||
self.tcx,
|
||||
param_env,
|
||||
query_state,
|
||||
@ -62,9 +63,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
},
|
||||
);
|
||||
|
||||
param_env.defining_opaque_types = self.defining_opaque_types;
|
||||
|
||||
Canonicalizer::canonicalize_with_base(
|
||||
let canonical = Canonicalizer::canonicalize_with_base(
|
||||
param_env,
|
||||
value,
|
||||
Some(self),
|
||||
@ -72,7 +71,8 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
&CanonicalizeAllFreeRegions,
|
||||
query_state,
|
||||
)
|
||||
.unchecked_map(|(param_env, value)| param_env.and(value))
|
||||
.unchecked_map(|(param_env, value)| param_env.and(value));
|
||||
CanonicalQueryInput { canonical, defining_opaque_types: self.defining_opaque_types() }
|
||||
}
|
||||
|
||||
/// Canonicalizes a query *response* `V`. When we canonicalize a
|
||||
@ -544,7 +544,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
||||
max_universe: ty::UniverseIndex::ROOT,
|
||||
variables: List::empty(),
|
||||
value: (),
|
||||
defining_opaque_types: infcx.map(|i| i.defining_opaque_types).unwrap_or_default(),
|
||||
};
|
||||
Canonicalizer::canonicalize_with_base(
|
||||
base,
|
||||
@ -614,15 +613,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
||||
.max()
|
||||
.unwrap_or(ty::UniverseIndex::ROOT);
|
||||
|
||||
assert!(
|
||||
!infcx.is_some_and(|infcx| infcx.defining_opaque_types != base.defining_opaque_types)
|
||||
);
|
||||
Canonical {
|
||||
max_universe,
|
||||
variables: canonical_variables,
|
||||
value: (base.value, out_value),
|
||||
defining_opaque_types: base.defining_opaque_types,
|
||||
}
|
||||
Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) }
|
||||
}
|
||||
|
||||
/// Creates a canonical variable replacing `kind` from the input,
|
||||
|
@ -25,7 +25,7 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_macros::extension;
|
||||
pub use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
|
||||
use rustc_middle::infer::unify_key::{
|
||||
ConstVariableOrigin, ConstVariableValue, ConstVidKey, EffectVarValue, EffectVidKey,
|
||||
};
|
||||
@ -606,14 +606,14 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
||||
pub fn build_with_canonical<T>(
|
||||
mut self,
|
||||
span: Span,
|
||||
canonical: &Canonical<'tcx, T>,
|
||||
input: &CanonicalQueryInput<'tcx, T>,
|
||||
) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>)
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.defining_opaque_types = canonical.defining_opaque_types;
|
||||
self.defining_opaque_types = input.defining_opaque_types;
|
||||
let infcx = self.build();
|
||||
let (value, args) = infcx.instantiate_canonical(span, canonical);
|
||||
let (value, args) = infcx.instantiate_canonical(span, &input.canonical);
|
||||
(infcx, value, args)
|
||||
}
|
||||
|
||||
@ -899,6 +899,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
ty::Const::new_var(self.tcx, vid)
|
||||
}
|
||||
|
||||
fn next_effect_var(&self) -> ty::Const<'tcx> {
|
||||
let effect_vid =
|
||||
self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid;
|
||||
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid))
|
||||
}
|
||||
|
||||
pub fn next_int_var(&self) -> Ty<'tcx> {
|
||||
let next_int_var_id =
|
||||
self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown);
|
||||
@ -1001,15 +1008,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
}
|
||||
|
||||
pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
|
||||
let effect_vid =
|
||||
self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid;
|
||||
let ty = self
|
||||
.tcx
|
||||
.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic");
|
||||
debug_assert_eq!(self.tcx.types.bool, ty);
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid)).into()
|
||||
self.next_effect_var().into()
|
||||
}
|
||||
|
||||
/// Given a set of generics defined on a type or impl, returns the generic parameters mapping
|
||||
|
@ -4,9 +4,12 @@ use rustc_data_structures::{snapshot_vec as sv, unify as ut};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableValue, ConstVidKey};
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
|
||||
use rustc_type_ir::EffectVid;
|
||||
use rustc_type_ir::visit::TypeVisitableExt;
|
||||
use tracing::instrument;
|
||||
use ut::UnifyKey;
|
||||
|
||||
use super::VariableLengths;
|
||||
use crate::infer::type_variable::TypeVariableOrigin;
|
||||
use crate::infer::{ConstVariableOrigin, InferCtxt, RegionVariableOrigin, UnificationTable};
|
||||
|
||||
@ -40,26 +43,7 @@ fn const_vars_since_snapshot<'tcx>(
|
||||
)
|
||||
}
|
||||
|
||||
struct VariableLengths {
|
||||
type_var_len: usize,
|
||||
const_var_len: usize,
|
||||
int_var_len: usize,
|
||||
float_var_len: usize,
|
||||
region_constraints_len: usize,
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
fn variable_lengths(&self) -> VariableLengths {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
VariableLengths {
|
||||
type_var_len: inner.type_variables().num_vars(),
|
||||
const_var_len: inner.const_unification_table().len(),
|
||||
int_var_len: inner.int_unification_table().len(),
|
||||
float_var_len: inner.float_unification_table().len(),
|
||||
region_constraints_len: inner.unwrap_region_constraints().num_region_vars(),
|
||||
}
|
||||
}
|
||||
|
||||
/// This rather funky routine is used while processing expected
|
||||
/// types. What happens here is that we want to propagate a
|
||||
/// coercion through the return type of a fn to its
|
||||
@ -106,78 +90,94 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let variable_lengths = self.variable_lengths();
|
||||
let (mut fudger, value) = self.probe(|_| {
|
||||
match f() {
|
||||
Ok(value) => {
|
||||
let value = self.resolve_vars_if_possible(value);
|
||||
|
||||
// At this point, `value` could in principle refer
|
||||
// to inference variables that have been created during
|
||||
// the snapshot. Once we exit `probe()`, those are
|
||||
// going to be popped, so we will have to
|
||||
// eliminate any references to them.
|
||||
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let type_vars =
|
||||
inner.type_variables().vars_since_snapshot(variable_lengths.type_var_len);
|
||||
let int_vars = vars_since_snapshot(
|
||||
&inner.int_unification_table(),
|
||||
variable_lengths.int_var_len,
|
||||
);
|
||||
let float_vars = vars_since_snapshot(
|
||||
&inner.float_unification_table(),
|
||||
variable_lengths.float_var_len,
|
||||
);
|
||||
let region_vars = inner
|
||||
.unwrap_region_constraints()
|
||||
.vars_since_snapshot(variable_lengths.region_constraints_len);
|
||||
let const_vars = const_vars_since_snapshot(
|
||||
&mut inner.const_unification_table(),
|
||||
variable_lengths.const_var_len,
|
||||
);
|
||||
|
||||
let fudger = InferenceFudger {
|
||||
infcx: self,
|
||||
type_vars,
|
||||
int_vars,
|
||||
float_vars,
|
||||
region_vars,
|
||||
const_vars,
|
||||
};
|
||||
|
||||
Ok((fudger, value))
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
let (snapshot_vars, value) = self.probe(|_| {
|
||||
let value = f()?;
|
||||
// At this point, `value` could in principle refer
|
||||
// to inference variables that have been created during
|
||||
// the snapshot. Once we exit `probe()`, those are
|
||||
// going to be popped, so we will have to
|
||||
// eliminate any references to them.
|
||||
let snapshot_vars = SnapshotVarData::new(self, variable_lengths);
|
||||
Ok((snapshot_vars, self.resolve_vars_if_possible(value)))
|
||||
})?;
|
||||
|
||||
// At this point, we need to replace any of the now-popped
|
||||
// type/region variables that appear in `value` with a fresh
|
||||
// variable of the appropriate kind. We can't do this during
|
||||
// the probe because they would just get popped then too. =)
|
||||
Ok(self.fudge_inference(snapshot_vars, value))
|
||||
}
|
||||
|
||||
fn fudge_inference<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
snapshot_vars: SnapshotVarData,
|
||||
value: T,
|
||||
) -> T {
|
||||
// Micro-optimization: if no variables have been created, then
|
||||
// `value` can't refer to any of them. =) So we can just return it.
|
||||
if fudger.type_vars.0.is_empty()
|
||||
&& fudger.int_vars.is_empty()
|
||||
&& fudger.float_vars.is_empty()
|
||||
&& fudger.region_vars.0.is_empty()
|
||||
&& fudger.const_vars.0.is_empty()
|
||||
{
|
||||
Ok(value)
|
||||
if snapshot_vars.is_empty() {
|
||||
value
|
||||
} else {
|
||||
Ok(value.fold_with(&mut fudger))
|
||||
value.fold_with(&mut InferenceFudger { infcx: self, snapshot_vars })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SnapshotVarData {
|
||||
region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>),
|
||||
type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
|
||||
int_vars: Range<IntVid>,
|
||||
float_vars: Range<FloatVid>,
|
||||
const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
|
||||
effect_vars: Range<EffectVid>,
|
||||
}
|
||||
|
||||
impl SnapshotVarData {
|
||||
fn new(infcx: &InferCtxt<'_>, vars_pre_snapshot: VariableLengths) -> SnapshotVarData {
|
||||
let mut inner = infcx.inner.borrow_mut();
|
||||
let region_vars = inner
|
||||
.unwrap_region_constraints()
|
||||
.vars_since_snapshot(vars_pre_snapshot.region_constraints_len);
|
||||
let type_vars = inner.type_variables().vars_since_snapshot(vars_pre_snapshot.type_var_len);
|
||||
let int_vars =
|
||||
vars_since_snapshot(&inner.int_unification_table(), vars_pre_snapshot.int_var_len);
|
||||
let float_vars =
|
||||
vars_since_snapshot(&inner.float_unification_table(), vars_pre_snapshot.float_var_len);
|
||||
|
||||
let const_vars = const_vars_since_snapshot(
|
||||
&mut inner.const_unification_table(),
|
||||
vars_pre_snapshot.const_var_len,
|
||||
);
|
||||
let effect_vars = vars_since_snapshot(
|
||||
&inner.effect_unification_table(),
|
||||
vars_pre_snapshot.effect_var_len,
|
||||
);
|
||||
let effect_vars = effect_vars.start.vid..effect_vars.end.vid;
|
||||
|
||||
SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars, effect_vars }
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
let SnapshotVarData {
|
||||
region_vars,
|
||||
type_vars,
|
||||
int_vars,
|
||||
float_vars,
|
||||
const_vars,
|
||||
effect_vars,
|
||||
} = self;
|
||||
region_vars.0.is_empty()
|
||||
&& type_vars.0.is_empty()
|
||||
&& int_vars.is_empty()
|
||||
&& float_vars.is_empty()
|
||||
&& const_vars.0.is_empty()
|
||||
&& effect_vars.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
struct InferenceFudger<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
|
||||
int_vars: Range<IntVid>,
|
||||
float_vars: Range<FloatVid>,
|
||||
region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>),
|
||||
const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
|
||||
snapshot_vars: SnapshotVarData,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
|
||||
@ -186,68 +186,93 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *ty.kind() {
|
||||
ty::Infer(ty::InferTy::TyVar(vid)) => {
|
||||
if self.type_vars.0.contains(&vid) {
|
||||
// This variable was created during the fudging.
|
||||
// Recreate it with a fresh variable here.
|
||||
let idx = vid.as_usize() - self.type_vars.0.start.as_usize();
|
||||
let origin = self.type_vars.1[idx];
|
||||
self.infcx.next_ty_var_with_origin(origin)
|
||||
} else {
|
||||
// This variable was created before the
|
||||
// "fudging". Since we refresh all type
|
||||
// variables to their binding anyhow, we know
|
||||
// that it is unbound, so we can just return
|
||||
// it.
|
||||
debug_assert!(
|
||||
self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()
|
||||
);
|
||||
ty
|
||||
if let &ty::Infer(infer_ty) = ty.kind() {
|
||||
match infer_ty {
|
||||
ty::TyVar(vid) => {
|
||||
if self.snapshot_vars.type_vars.0.contains(&vid) {
|
||||
// This variable was created during the fudging.
|
||||
// Recreate it with a fresh variable here.
|
||||
let idx = vid.as_usize() - self.snapshot_vars.type_vars.0.start.as_usize();
|
||||
let origin = self.snapshot_vars.type_vars.1[idx];
|
||||
self.infcx.next_ty_var_with_origin(origin)
|
||||
} else {
|
||||
// This variable was created before the
|
||||
// "fudging". Since we refresh all type
|
||||
// variables to their binding anyhow, we know
|
||||
// that it is unbound, so we can just return
|
||||
// it.
|
||||
debug_assert!(
|
||||
self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()
|
||||
);
|
||||
ty
|
||||
}
|
||||
}
|
||||
ty::IntVar(vid) => {
|
||||
if self.snapshot_vars.int_vars.contains(&vid) {
|
||||
self.infcx.next_int_var()
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
ty::FloatVar(vid) => {
|
||||
if self.snapshot_vars.float_vars.contains(&vid) {
|
||||
self.infcx.next_float_var()
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
|
||||
unreachable!("unexpected fresh infcx var")
|
||||
}
|
||||
}
|
||||
ty::Infer(ty::InferTy::IntVar(vid)) => {
|
||||
if self.int_vars.contains(&vid) {
|
||||
self.infcx.next_int_var()
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
ty::Infer(ty::InferTy::FloatVar(vid)) => {
|
||||
if self.float_vars.contains(&vid) {
|
||||
self.infcx.next_float_var()
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
_ => ty.super_fold_with(self),
|
||||
} else if ty.has_infer() {
|
||||
ty.super_fold_with(self)
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
if let ty::ReVar(vid) = *r
|
||||
&& self.region_vars.0.contains(&vid)
|
||||
{
|
||||
let idx = vid.index() - self.region_vars.0.start.index();
|
||||
let origin = self.region_vars.1[idx];
|
||||
return self.infcx.next_region_var(origin);
|
||||
if let ty::ReVar(vid) = r.kind() {
|
||||
if self.snapshot_vars.region_vars.0.contains(&vid) {
|
||||
let idx = vid.index() - self.snapshot_vars.region_vars.0.start.index();
|
||||
let origin = self.snapshot_vars.region_vars.1[idx];
|
||||
self.infcx.next_region_var(origin)
|
||||
} else {
|
||||
r
|
||||
}
|
||||
} else {
|
||||
r
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
|
||||
if self.const_vars.0.contains(&vid) {
|
||||
// This variable was created during the fudging.
|
||||
// Recreate it with a fresh variable here.
|
||||
let idx = vid.index() - self.const_vars.0.start.index();
|
||||
let origin = self.const_vars.1[idx];
|
||||
self.infcx.next_const_var_with_origin(origin)
|
||||
} else {
|
||||
ct
|
||||
if let ty::ConstKind::Infer(infer_ct) = ct.kind() {
|
||||
match infer_ct {
|
||||
ty::InferConst::Var(vid) => {
|
||||
if self.snapshot_vars.const_vars.0.contains(&vid) {
|
||||
let idx = vid.index() - self.snapshot_vars.const_vars.0.start.index();
|
||||
let origin = self.snapshot_vars.const_vars.1[idx];
|
||||
self.infcx.next_const_var_with_origin(origin)
|
||||
} else {
|
||||
ct
|
||||
}
|
||||
}
|
||||
ty::InferConst::EffectVar(vid) => {
|
||||
if self.snapshot_vars.effect_vars.contains(&vid) {
|
||||
self.infcx.next_effect_var()
|
||||
} else {
|
||||
ct
|
||||
}
|
||||
}
|
||||
ty::InferConst::Fresh(_) => {
|
||||
unreachable!("unexpected fresh infcx var")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if ct.has_infer() {
|
||||
ct.super_fold_with(self)
|
||||
} else {
|
||||
ct
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,28 @@ pub struct CombinedSnapshot<'tcx> {
|
||||
universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
struct VariableLengths {
|
||||
region_constraints_len: usize,
|
||||
type_var_len: usize,
|
||||
int_var_len: usize,
|
||||
float_var_len: usize,
|
||||
const_var_len: usize,
|
||||
effect_var_len: usize,
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
fn variable_lengths(&self) -> VariableLengths {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
VariableLengths {
|
||||
region_constraints_len: inner.unwrap_region_constraints().num_region_vars(),
|
||||
type_var_len: inner.type_variables().num_vars(),
|
||||
int_var_len: inner.int_unification_table().len(),
|
||||
float_var_len: inner.float_unification_table().len(),
|
||||
const_var_len: inner.const_unification_table().len(),
|
||||
effect_var_len: inner.effect_unification_table().len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn in_snapshot(&self) -> bool {
|
||||
UndoLogs::<UndoLog<'tcx>>::in_snapshot(&self.inner.borrow_mut().undo_log)
|
||||
}
|
||||
|
@ -2601,7 +2601,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
|
||||
ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init))
|
||||
}
|
||||
Array(ty, len) => {
|
||||
if matches!(len.try_eval_target_usize(cx.tcx, cx.param_env), Some(v) if v > 0) {
|
||||
if matches!(len.try_to_target_usize(cx.tcx), Some(v) if v > 0) {
|
||||
// Array length known at array non-empty -- recurse.
|
||||
ty_find_init_error(cx, *ty, init)
|
||||
} else {
|
||||
|
@ -493,7 +493,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
||||
//
|
||||
// This means that this only errors if we're truly lowering the lint
|
||||
// level from forbid.
|
||||
if self.lint_added_lints && level != Level::Forbid && old_level == Level::Forbid {
|
||||
if self.lint_added_lints && level == Level::Deny && old_level == Level::Forbid {
|
||||
// Having a deny inside a forbid is fine and is ignored, so we skip this check.
|
||||
return;
|
||||
} else if self.lint_added_lints && level != Level::Forbid && old_level == Level::Forbid {
|
||||
// Backwards compatibility check:
|
||||
//
|
||||
// We used to not consider `forbid(lint_group)`
|
||||
|
@ -598,6 +598,7 @@ fn register_builtins(store: &mut LintStore) {
|
||||
"converted into hard error, see PR #125380 \
|
||||
<https://github.com/rust-lang/rust/pull/125380> for more information",
|
||||
);
|
||||
store.register_removed("unsupported_calling_conventions", "converted into hard error");
|
||||
}
|
||||
|
||||
fn register_internals(store: &mut LintStore) {
|
||||
|
@ -18,6 +18,8 @@ use rustc_target::spec::abi::Abi as SpecAbi;
|
||||
use tracing::debug;
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
mod improper_ctypes;
|
||||
|
||||
use crate::lints::{
|
||||
AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
|
||||
AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
|
||||
@ -728,7 +730,6 @@ fn is_niche_optimization_candidate<'tcx>(
|
||||
/// can, return the type that `ty` can be safely converted to, otherwise return `None`.
|
||||
/// Currently restricted to function pointers, boxes, references, `core::num::NonZero`,
|
||||
/// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
|
||||
/// FIXME: This duplicates code in codegen.
|
||||
pub(crate) fn repr_nullable_ptr<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
@ -741,10 +742,6 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
|
||||
[var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
|
||||
([], [field]) | ([field], []) => field.ty(tcx, args),
|
||||
([field1], [field2]) => {
|
||||
if !tcx.features().result_ffi_guarantees {
|
||||
return None;
|
||||
}
|
||||
|
||||
let ty1 = field1.ty(tcx, args);
|
||||
let ty2 = field2.ty(tcx, args);
|
||||
|
||||
@ -983,15 +980,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
// Empty enums are okay... although sort of useless.
|
||||
return FfiSafe;
|
||||
}
|
||||
|
||||
if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
|
||||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_non_exhaustive,
|
||||
help: None,
|
||||
};
|
||||
}
|
||||
|
||||
// Check for a repr() attribute to specify the size of the
|
||||
// discriminant.
|
||||
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
|
||||
@ -1010,21 +998,23 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
};
|
||||
}
|
||||
|
||||
use improper_ctypes::{
|
||||
check_non_exhaustive_variant, non_local_and_non_exhaustive,
|
||||
};
|
||||
|
||||
let non_local_def = non_local_and_non_exhaustive(def);
|
||||
// Check the contained variants.
|
||||
for variant in def.variants() {
|
||||
let is_non_exhaustive = variant.is_field_list_non_exhaustive();
|
||||
if is_non_exhaustive && !variant.def_id.is_local() {
|
||||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_non_exhaustive_variant,
|
||||
help: None,
|
||||
};
|
||||
}
|
||||
let ret = def.variants().iter().try_for_each(|variant| {
|
||||
check_non_exhaustive_variant(non_local_def, variant)
|
||||
.map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
|
||||
|
||||
match self.check_variant_for_ffi(acc, ty, def, variant, args) {
|
||||
FfiSafe => (),
|
||||
r => return r,
|
||||
FfiSafe => ControlFlow::Continue(()),
|
||||
r => ControlFlow::Break(r),
|
||||
}
|
||||
});
|
||||
if let ControlFlow::Break(result) = ret {
|
||||
return result;
|
||||
}
|
||||
|
||||
FfiSafe
|
||||
|
51
compiler/rustc_lint/src/types/improper_ctypes.rs
Normal file
51
compiler/rustc_lint/src/types/improper_ctypes.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_errors::DiagMessage;
|
||||
use rustc_hir::def::CtorKind;
|
||||
use rustc_middle::ty;
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
/// Check a variant of a non-exhaustive enum for improper ctypes
|
||||
///
|
||||
/// We treat `#[non_exhaustive] enum` as "ensure that code will compile if new variants are added".
|
||||
/// This includes linting, on a best-effort basis. There are valid additions that are unlikely.
|
||||
///
|
||||
/// Adding a data-carrying variant to an existing C-like enum that is passed to C is "unlikely",
|
||||
/// so we don't need the lint to account for it.
|
||||
/// e.g. going from enum Foo { A, B, C } to enum Foo { A, B, C, D(u32) }.
|
||||
pub(crate) fn check_non_exhaustive_variant(
|
||||
non_local_def: bool,
|
||||
variant: &ty::VariantDef,
|
||||
) -> ControlFlow<DiagMessage, ()> {
|
||||
// non_exhaustive suggests it is possible that someone might break ABI
|
||||
// see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344
|
||||
// so warn on complex enums being used outside their crate
|
||||
if non_local_def {
|
||||
// which is why we only warn about really_tagged_union reprs from https://rust.tf/rfc2195
|
||||
// with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }`
|
||||
// but exempt enums with unit ctors like C's (e.g. from rust-bindgen)
|
||||
if variant_has_complex_ctor(variant) {
|
||||
return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive);
|
||||
}
|
||||
}
|
||||
|
||||
let non_exhaustive_variant_fields = variant.is_field_list_non_exhaustive();
|
||||
if non_exhaustive_variant_fields && !variant.def_id.is_local() {
|
||||
return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive_variant);
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
|
||||
// CtorKind::Const means a "unit" ctor
|
||||
!matches!(variant.ctor_kind(), Some(CtorKind::Const))
|
||||
}
|
||||
|
||||
// non_exhaustive suggests it is possible that someone might break ABI
|
||||
// see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344
|
||||
// so warn on complex enums being used outside their crate
|
||||
pub(crate) fn non_local_and_non_exhaustive(def: ty::AdtDef<'_>) -> bool {
|
||||
def.is_variant_list_non_exhaustive() && !def.did().is_local()
|
||||
}
|
@ -346,7 +346,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
||||
None
|
||||
}
|
||||
}
|
||||
ty::Array(ty, len) => match len.try_eval_target_usize(cx.tcx, cx.param_env) {
|
||||
ty::Array(ty, len) => match len.try_to_target_usize(cx.tcx) {
|
||||
// If the array is empty we don't lint, to avoid false positives
|
||||
Some(0) | None => None,
|
||||
// If the array is definitely non-empty, we can do `#[must_use]` checking.
|
||||
|
@ -123,7 +123,6 @@ declare_lint_pass! {
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
UNSTABLE_NAME_COLLISIONS,
|
||||
UNSTABLE_SYNTAX_PRE_EXPANSION,
|
||||
UNSUPPORTED_CALLING_CONVENTIONS,
|
||||
UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
|
||||
UNUSED_ASSIGNMENTS,
|
||||
UNUSED_ASSOCIATED_TYPE_BOUNDS,
|
||||
@ -156,7 +155,7 @@ declare_lint! {
|
||||
///
|
||||
/// ```rust
|
||||
/// #![forbid(warnings)]
|
||||
/// #![deny(bad_style)]
|
||||
/// #![warn(bad_style)]
|
||||
///
|
||||
/// fn main() {}
|
||||
/// ```
|
||||
@ -2667,7 +2666,6 @@ declare_lint! {
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(strict_provenance)]
|
||||
/// #![warn(fuzzy_provenance_casts)]
|
||||
///
|
||||
/// fn main() {
|
||||
@ -2701,7 +2699,7 @@ declare_lint! {
|
||||
pub FUZZY_PROVENANCE_CASTS,
|
||||
Allow,
|
||||
"a fuzzy integer to pointer cast is used",
|
||||
@feature_gate = strict_provenance;
|
||||
@feature_gate = strict_provenance_lints;
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
@ -2711,7 +2709,6 @@ declare_lint! {
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(strict_provenance)]
|
||||
/// #![warn(lossy_provenance_casts)]
|
||||
///
|
||||
/// fn main() {
|
||||
@ -2747,7 +2744,7 @@ declare_lint! {
|
||||
pub LOSSY_PROVENANCE_CASTS,
|
||||
Allow,
|
||||
"a lossy pointer to integer cast is used",
|
||||
@feature_gate = strict_provenance;
|
||||
@feature_gate = strict_provenance_lints;
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
@ -3789,53 +3786,6 @@ declare_lint! {
|
||||
crate_level_only
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unsupported_calling_conventions` lint is output whenever there is a use of the
|
||||
/// `stdcall`, `fastcall`, `thiscall`, `vectorcall` calling conventions (or their unwind
|
||||
/// variants) on targets that cannot meaningfully be supported for the requested target.
|
||||
///
|
||||
/// For example `stdcall` does not make much sense for a x86_64 or, more apparently, powerpc
|
||||
/// code, because this calling convention was never specified for those targets.
|
||||
///
|
||||
/// Historically MSVC toolchains have fallen back to the regular C calling convention for
|
||||
/// targets other than x86, but Rust doesn't really see a similar need to introduce a similar
|
||||
/// hack across many more targets.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,ignore (needs specific targets)
|
||||
/// extern "stdcall" fn stdcall() {}
|
||||
/// ```
|
||||
///
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// warning: use of calling convention not supported on this target
|
||||
/// --> $DIR/unsupported.rs:39:1
|
||||
/// |
|
||||
/// LL | extern "stdcall" fn stdcall() {}
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// |
|
||||
/// = note: `#[warn(unsupported_calling_conventions)]` on by default
|
||||
/// = warning: this was previously accepted by the compiler but is being phased out;
|
||||
/// it will become a hard error in a future release!
|
||||
/// = note: for more information, see issue ...
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// On most of the targets the behaviour of `stdcall` and similar calling conventions is not
|
||||
/// defined at all, but was previously accepted due to a bug in the implementation of the
|
||||
/// compiler.
|
||||
pub UNSUPPORTED_CALLING_CONVENTIONS,
|
||||
Warn,
|
||||
"use of unsupported calling convention",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
|
||||
reference: "issue #87678 <https://github.com/rust-lang/rust/issues/87678>",
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unsupported_fn_ptr_calling_conventions` lint is output whenever there is a use of
|
||||
/// a target dependent calling convention on a target that does not support this calling
|
||||
|
@ -490,13 +490,13 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
|
||||
assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0');
|
||||
auto Arg0 = std::string(ArgsCstrBuff);
|
||||
buffer_offset = Arg0.size() + 1;
|
||||
auto ArgsCppStr =
|
||||
std::string(ArgsCstrBuff + buffer_offset, ArgsCstrBuffLen - 1);
|
||||
auto ArgsCppStr = std::string(ArgsCstrBuff + buffer_offset,
|
||||
ArgsCstrBuffLen - buffer_offset);
|
||||
auto i = 0;
|
||||
while (i != std::string::npos) {
|
||||
i = ArgsCppStr.find('\0', i + 1);
|
||||
if (i != std::string::npos)
|
||||
ArgsCppStr.replace(i, i + 1, " ");
|
||||
ArgsCppStr.replace(i, 1, " ");
|
||||
}
|
||||
Options.MCOptions.Argv0 = Arg0;
|
||||
Options.MCOptions.CommandlineArgs = ArgsCppStr;
|
||||
|
@ -1658,16 +1658,6 @@ extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B,
|
||||
unwrap(B)->SetInsertPoint(unwrap(BB), Point);
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V,
|
||||
const char *Name, size_t NameLen) {
|
||||
Triple TargetTriple = Triple(unwrap(M)->getTargetTriple());
|
||||
GlobalObject *GV = unwrap<GlobalObject>(V);
|
||||
if (TargetTriple.supportsCOMDAT()) {
|
||||
StringRef NameRef(Name, NameLen);
|
||||
GV->setComdat(unwrap(M)->getOrInsertComdat(NameRef));
|
||||
}
|
||||
}
|
||||
|
||||
enum class LLVMRustLinkage {
|
||||
ExternalLinkage = 0,
|
||||
AvailableExternallyLinkage = 1,
|
||||
|
@ -499,8 +499,11 @@ impl<'a> CrateLocator<'a> {
|
||||
dylibs: FxIndexMap<PathBuf, PathKind>,
|
||||
) -> Result<Option<(Svh, Library)>, CrateError> {
|
||||
let mut slot = None;
|
||||
// Order here matters, rmeta should come first. See comment in
|
||||
// `extract_one` below.
|
||||
// Order here matters, rmeta should come first.
|
||||
//
|
||||
// Make sure there's at most one rlib and at most one dylib.
|
||||
//
|
||||
// See comment in `extract_one` below.
|
||||
let source = CrateSource {
|
||||
rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?,
|
||||
rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?,
|
||||
@ -706,54 +709,58 @@ impl<'a> CrateLocator<'a> {
|
||||
let mut rmetas = FxIndexMap::default();
|
||||
let mut dylibs = FxIndexMap::default();
|
||||
for loc in &self.exact_paths {
|
||||
if !loc.canonicalized().exists() {
|
||||
return Err(CrateError::ExternLocationNotExist(
|
||||
self.crate_name,
|
||||
loc.original().clone(),
|
||||
));
|
||||
let loc_canon = loc.canonicalized();
|
||||
let loc_orig = loc.original();
|
||||
if !loc_canon.exists() {
|
||||
return Err(CrateError::ExternLocationNotExist(self.crate_name, loc_orig.clone()));
|
||||
}
|
||||
if !loc.original().is_file() {
|
||||
return Err(CrateError::ExternLocationNotFile(
|
||||
self.crate_name,
|
||||
loc.original().clone(),
|
||||
));
|
||||
if !loc_orig.is_file() {
|
||||
return Err(CrateError::ExternLocationNotFile(self.crate_name, loc_orig.clone()));
|
||||
}
|
||||
let Some(file) = loc.original().file_name().and_then(|s| s.to_str()) else {
|
||||
return Err(CrateError::ExternLocationNotFile(
|
||||
self.crate_name,
|
||||
loc.original().clone(),
|
||||
));
|
||||
// Note to take care and match against the non-canonicalized name:
|
||||
// some systems save build artifacts into content-addressed stores
|
||||
// that do not preserve extensions, and then link to them using
|
||||
// e.g. symbolic links. If we canonicalize too early, we resolve
|
||||
// the symlink, the file type is lost and we might treat rlibs and
|
||||
// rmetas as dylibs.
|
||||
let Some(file) = loc_orig.file_name().and_then(|s| s.to_str()) else {
|
||||
return Err(CrateError::ExternLocationNotFile(self.crate_name, loc_orig.clone()));
|
||||
};
|
||||
|
||||
if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta"))
|
||||
|| file.starts_with(self.target.dll_prefix.as_ref())
|
||||
&& file.ends_with(self.target.dll_suffix.as_ref())
|
||||
{
|
||||
// Make sure there's at most one rlib and at most one dylib.
|
||||
// Note to take care and match against the non-canonicalized name:
|
||||
// some systems save build artifacts into content-addressed stores
|
||||
// that do not preserve extensions, and then link to them using
|
||||
// e.g. symbolic links. If we canonicalize too early, we resolve
|
||||
// the symlink, the file type is lost and we might treat rlibs and
|
||||
// rmetas as dylibs.
|
||||
let loc_canon = loc.canonicalized().clone();
|
||||
let loc = loc.original();
|
||||
if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
|
||||
rlibs.insert(loc_canon, PathKind::ExternFlag);
|
||||
} else if loc.file_name().unwrap().to_str().unwrap().ends_with(".rmeta") {
|
||||
rmetas.insert(loc_canon, PathKind::ExternFlag);
|
||||
} else {
|
||||
dylibs.insert(loc_canon, PathKind::ExternFlag);
|
||||
// FnMut cannot return reference to captured value, so references
|
||||
// must be taken outside the closure.
|
||||
let rlibs = &mut rlibs;
|
||||
let rmetas = &mut rmetas;
|
||||
let dylibs = &mut dylibs;
|
||||
let type_via_filename = (|| {
|
||||
if file.starts_with("lib") {
|
||||
if file.ends_with(".rlib") {
|
||||
return Some(rlibs);
|
||||
}
|
||||
if file.ends_with(".rmeta") {
|
||||
return Some(rmetas);
|
||||
}
|
||||
}
|
||||
let dll_prefix = self.target.dll_prefix.as_ref();
|
||||
let dll_suffix = self.target.dll_suffix.as_ref();
|
||||
if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) {
|
||||
return Some(dylibs);
|
||||
}
|
||||
None
|
||||
})();
|
||||
match type_via_filename {
|
||||
Some(type_via_filename) => {
|
||||
type_via_filename.insert(loc_canon.clone(), PathKind::ExternFlag);
|
||||
}
|
||||
None => {
|
||||
self.crate_rejections
|
||||
.via_filename
|
||||
.push(CrateMismatch { path: loc_orig.clone(), got: String::new() });
|
||||
}
|
||||
} else {
|
||||
self.crate_rejections
|
||||
.via_filename
|
||||
.push(CrateMismatch { path: loc.original().clone(), got: String::new() });
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the dylib/rlib/rmeta triple.
|
||||
Ok(self.extract_lib(rlibs, rmetas, dylibs)?.map(|(_, lib)| lib))
|
||||
self.extract_lib(rlibs, rmetas, dylibs).map(|opt| opt.map(|(_, lib)| lib))
|
||||
}
|
||||
|
||||
pub(crate) fn into_error(self, root: Option<CratePaths>) -> CrateError {
|
||||
|
@ -437,9 +437,6 @@ provide! { tcx, def_id, other, cdata,
|
||||
|
||||
pub(in crate::rmeta) fn provide(providers: &mut Providers) {
|
||||
provide_cstore_hooks(providers);
|
||||
// FIXME(#44234) - almost all of these queries have no sub-queries and
|
||||
// therefore no actual inputs, they're just reading tables calculated in
|
||||
// resolve! Does this work? Unsure! That's what the issue is about
|
||||
providers.queries = rustc_middle::query::Providers {
|
||||
allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(),
|
||||
alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(),
|
||||
|
@ -34,6 +34,7 @@ use crate::infer::MemberConstraint;
|
||||
use crate::mir::ConstraintCategory;
|
||||
use crate::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
|
||||
|
||||
pub type CanonicalQueryInput<'tcx, V> = ir::CanonicalQueryInput<TyCtxt<'tcx>, V>;
|
||||
pub type Canonical<'tcx, V> = ir::Canonical<TyCtxt<'tcx>, V>;
|
||||
pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo<TyCtxt<'tcx>>;
|
||||
pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>;
|
||||
@ -182,7 +183,6 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> {
|
||||
max_universe: ty::UniverseIndex::ROOT,
|
||||
variables: List::empty(),
|
||||
value: key,
|
||||
defining_opaque_types: ty::List::empty(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,6 @@
|
||||
#![feature(ptr_alignment_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(trait_upcasting)]
|
||||
#![feature(trusted_len)]
|
||||
#![feature(try_blocks)]
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
|
||||
use either::Either;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
use rustc_session::RemapFileNameExt;
|
||||
@ -320,8 +321,14 @@ impl<'tcx> Const<'tcx> {
|
||||
Const::Ty(_, c) => {
|
||||
// We want to consistently have a "clean" value for type system constants (i.e., no
|
||||
// data hidden in the padding), so we always go through a valtree here.
|
||||
let (ty, val) = c.eval(tcx, param_env, span)?;
|
||||
Ok(tcx.valtree_to_const_val((ty, val)))
|
||||
match c.eval_valtree(tcx, param_env, span) {
|
||||
Ok((ty, val)) => Ok(tcx.valtree_to_const_val((ty, val))),
|
||||
Err(Either::Left(_bad_ty)) => Err(tcx
|
||||
.dcx()
|
||||
.delayed_bug("`mir::Const::eval` called on a non-valtree-compatible type")
|
||||
.into()),
|
||||
Err(Either::Right(e)) => Err(e),
|
||||
}
|
||||
}
|
||||
Const::Unevaluated(uneval, _) => {
|
||||
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
|
||||
|
@ -18,9 +18,9 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
use rustc_target::abi::{Align, HasDataLayout, Size};
|
||||
|
||||
use super::{
|
||||
AllocId, BadBytesAccess, CtfeProvenance, InterpError, InterpResult, Pointer, PointerArithmetic,
|
||||
Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, UndefinedBehaviorInfo,
|
||||
UnsupportedOpInfo, interp_ok, read_target_uint, write_target_uint,
|
||||
AllocId, BadBytesAccess, CtfeProvenance, InterpErrorKind, InterpResult, Pointer,
|
||||
PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch,
|
||||
UndefinedBehaviorInfo, UnsupportedOpInfo, interp_ok, read_target_uint, write_target_uint,
|
||||
};
|
||||
use crate::ty;
|
||||
|
||||
@ -199,22 +199,22 @@ impl From<ScalarSizeMismatch> for AllocError {
|
||||
}
|
||||
|
||||
impl AllocError {
|
||||
pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpError<'tcx> {
|
||||
pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpErrorKind<'tcx> {
|
||||
use AllocError::*;
|
||||
match self {
|
||||
ScalarSizeMismatch(s) => {
|
||||
InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ScalarSizeMismatch(s))
|
||||
InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::ScalarSizeMismatch(s))
|
||||
}
|
||||
ReadPointerAsInt(info) => InterpError::Unsupported(
|
||||
ReadPointerAsInt(info) => InterpErrorKind::Unsupported(
|
||||
UnsupportedOpInfo::ReadPointerAsInt(info.map(|b| (alloc_id, b))),
|
||||
),
|
||||
OverwritePartialPointer(offset) => InterpError::Unsupported(
|
||||
OverwritePartialPointer(offset) => InterpErrorKind::Unsupported(
|
||||
UnsupportedOpInfo::OverwritePartialPointer(Pointer::new(alloc_id, offset)),
|
||||
),
|
||||
ReadPartialPointer(offset) => InterpError::Unsupported(
|
||||
ReadPartialPointer(offset) => InterpErrorKind::Unsupported(
|
||||
UnsupportedOpInfo::ReadPartialPointer(Pointer::new(alloc_id, offset)),
|
||||
),
|
||||
InvalidUninitBytes(info) => InterpError::UndefinedBehavior(
|
||||
InvalidUninitBytes(info) => InterpErrorKind::UndefinedBehavior(
|
||||
UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))),
|
||||
),
|
||||
}
|
||||
@ -318,7 +318,7 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
||||
pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> {
|
||||
Self::uninit_inner(size, align, || {
|
||||
ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation"));
|
||||
InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
|
||||
InterpErrorKind::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InterpErrorInfoInner<'tcx> {
|
||||
kind: InterpError<'tcx>,
|
||||
kind: InterpErrorKind<'tcx>,
|
||||
backtrace: InterpErrorBacktrace,
|
||||
}
|
||||
|
||||
@ -154,21 +154,21 @@ impl InterpErrorBacktrace {
|
||||
}
|
||||
|
||||
impl<'tcx> InterpErrorInfo<'tcx> {
|
||||
pub fn into_parts(self) -> (InterpError<'tcx>, InterpErrorBacktrace) {
|
||||
pub fn into_parts(self) -> (InterpErrorKind<'tcx>, InterpErrorBacktrace) {
|
||||
let InterpErrorInfo(box InterpErrorInfoInner { kind, backtrace }) = self;
|
||||
(kind, backtrace)
|
||||
}
|
||||
|
||||
pub fn into_kind(self) -> InterpError<'tcx> {
|
||||
pub fn into_kind(self) -> InterpErrorKind<'tcx> {
|
||||
self.0.kind
|
||||
}
|
||||
|
||||
pub fn from_parts(kind: InterpError<'tcx>, backtrace: InterpErrorBacktrace) -> Self {
|
||||
pub fn from_parts(kind: InterpErrorKind<'tcx>, backtrace: InterpErrorBacktrace) -> Self {
|
||||
Self(Box::new(InterpErrorInfoInner { kind, backtrace }))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn kind(&self) -> &InterpError<'tcx> {
|
||||
pub fn kind(&self) -> &InterpErrorKind<'tcx> {
|
||||
&self.0.kind
|
||||
}
|
||||
}
|
||||
@ -179,13 +179,13 @@ fn print_backtrace(backtrace: &Backtrace) {
|
||||
|
||||
impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
|
||||
fn from(err: ErrorGuaranteed) -> Self {
|
||||
InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into()
|
||||
InterpErrorKind::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorHandled> for InterpErrorInfo<'_> {
|
||||
fn from(err: ErrorHandled) -> Self {
|
||||
InterpError::InvalidProgram(match err {
|
||||
InterpErrorKind::InvalidProgram(match err {
|
||||
ErrorHandled::Reported(r, _span) => InvalidProgramInfo::AlreadyReported(r),
|
||||
ErrorHandled::TooGeneric(_span) => InvalidProgramInfo::TooGeneric,
|
||||
})
|
||||
@ -193,8 +193,8 @@ impl From<ErrorHandled> for InterpErrorInfo<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
|
||||
fn from(kind: InterpError<'tcx>) -> Self {
|
||||
impl<'tcx> From<InterpErrorKind<'tcx>> for InterpErrorInfo<'tcx> {
|
||||
fn from(kind: InterpErrorKind<'tcx>) -> Self {
|
||||
InterpErrorInfo(Box::new(InterpErrorInfoInner {
|
||||
kind,
|
||||
backtrace: InterpErrorBacktrace::new(),
|
||||
@ -590,7 +590,7 @@ impl dyn MachineStopType {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InterpError<'tcx> {
|
||||
pub enum InterpErrorKind<'tcx> {
|
||||
/// The program caused undefined behavior.
|
||||
UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
|
||||
/// The program did something the interpreter does not support (some of these *might* be UB
|
||||
@ -606,25 +606,25 @@ pub enum InterpError<'tcx> {
|
||||
MachineStop(Box<dyn MachineStopType>),
|
||||
}
|
||||
|
||||
impl InterpError<'_> {
|
||||
impl InterpErrorKind<'_> {
|
||||
/// Some errors do string formatting even if the error is never printed.
|
||||
/// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
|
||||
/// so this method lets us detect them and `bug!` on unexpected errors.
|
||||
pub fn formatted_string(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
|
||||
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationError { .. })
|
||||
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
|
||||
InterpErrorKind::Unsupported(UnsupportedOpInfo::Unsupported(_))
|
||||
| InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::ValidationError { .. })
|
||||
| InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Macros for constructing / throwing `InterpError`
|
||||
// Macros for constructing / throwing `InterpErrorKind`
|
||||
#[macro_export]
|
||||
macro_rules! err_unsup {
|
||||
($($tt:tt)*) => {
|
||||
$crate::mir::interpret::InterpError::Unsupported(
|
||||
$crate::mir::interpret::InterpErrorKind::Unsupported(
|
||||
$crate::mir::interpret::UnsupportedOpInfo::$($tt)*
|
||||
)
|
||||
};
|
||||
@ -638,7 +638,7 @@ macro_rules! err_unsup_format {
|
||||
#[macro_export]
|
||||
macro_rules! err_inval {
|
||||
($($tt:tt)*) => {
|
||||
$crate::mir::interpret::InterpError::InvalidProgram(
|
||||
$crate::mir::interpret::InterpErrorKind::InvalidProgram(
|
||||
$crate::mir::interpret::InvalidProgramInfo::$($tt)*
|
||||
)
|
||||
};
|
||||
@ -647,7 +647,7 @@ macro_rules! err_inval {
|
||||
#[macro_export]
|
||||
macro_rules! err_ub {
|
||||
($($tt:tt)*) => {
|
||||
$crate::mir::interpret::InterpError::UndefinedBehavior(
|
||||
$crate::mir::interpret::InterpErrorKind::UndefinedBehavior(
|
||||
$crate::mir::interpret::UndefinedBehaviorInfo::$($tt)*
|
||||
)
|
||||
};
|
||||
@ -680,7 +680,7 @@ macro_rules! err_ub_custom {
|
||||
#[macro_export]
|
||||
macro_rules! err_exhaust {
|
||||
($($tt:tt)*) => {
|
||||
$crate::mir::interpret::InterpError::ResourceExhaustion(
|
||||
$crate::mir::interpret::InterpErrorKind::ResourceExhaustion(
|
||||
$crate::mir::interpret::ResourceExhaustionInfo::$($tt)*
|
||||
)
|
||||
};
|
||||
@ -689,7 +689,7 @@ macro_rules! err_exhaust {
|
||||
#[macro_export]
|
||||
macro_rules! err_machine_stop {
|
||||
($($tt:tt)*) => {
|
||||
$crate::mir::interpret::InterpError::MachineStop(Box::new($($tt)*))
|
||||
$crate::mir::interpret::InterpErrorKind::MachineStop(Box::new($($tt)*))
|
||||
};
|
||||
}
|
||||
|
||||
@ -792,9 +792,9 @@ impl<'tcx, T> ops::FromResidual for InterpResult_<'tcx, T> {
|
||||
}
|
||||
|
||||
// Allow `yeet`ing `InterpError` in functions returning `InterpResult_`.
|
||||
impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpError<'tcx>>> for InterpResult_<'tcx, T> {
|
||||
impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResult_<'tcx, T> {
|
||||
#[inline]
|
||||
fn from_residual(ops::Yeet(e): ops::Yeet<InterpError<'tcx>>) -> Self {
|
||||
fn from_residual(ops::Yeet(e): ops::Yeet<InterpErrorKind<'tcx>>) -> Self {
|
||||
Self::new(Err(e.into()))
|
||||
}
|
||||
}
|
||||
@ -856,7 +856,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn map_err(
|
||||
pub fn map_err_info(
|
||||
self,
|
||||
f: impl FnOnce(InterpErrorInfo<'tcx>) -> InterpErrorInfo<'tcx>,
|
||||
) -> InterpResult<'tcx, T> {
|
||||
@ -864,8 +864,19 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inspect_err(self, f: impl FnOnce(&InterpErrorInfo<'tcx>)) -> InterpResult<'tcx, T> {
|
||||
InterpResult_::new(self.disarm().inspect_err(f))
|
||||
pub fn map_err_kind(
|
||||
self,
|
||||
f: impl FnOnce(InterpErrorKind<'tcx>) -> InterpErrorKind<'tcx>,
|
||||
) -> InterpResult<'tcx, T> {
|
||||
InterpResult_::new(self.disarm().map_err(|mut e| {
|
||||
e.0.kind = f(e.0.kind);
|
||||
e
|
||||
}))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inspect_err_kind(self, f: impl FnOnce(&InterpErrorKind<'tcx>)) -> InterpResult<'tcx, T> {
|
||||
InterpResult_::new(self.disarm().inspect_err(|e| f(&e.0.kind)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -36,7 +36,7 @@ pub use self::allocation::{
|
||||
pub use self::error::{
|
||||
BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult,
|
||||
EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind,
|
||||
InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo,
|
||||
InterpErrorInfo, InterpErrorKind, InterpResult, InvalidMetaKind, InvalidProgramInfo,
|
||||
MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo,
|
||||
ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
|
||||
ValidationErrorKind, interp_ok,
|
||||
|
@ -55,7 +55,7 @@ impl<'tcx> PlaceTy<'tcx> {
|
||||
/// `PlaceElem`, where we can just use the `Ty` that is already
|
||||
/// stored inline on field projection elems.
|
||||
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
|
||||
self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty)
|
||||
self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty)
|
||||
}
|
||||
|
||||
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
|
||||
@ -66,7 +66,6 @@ impl<'tcx> PlaceTy<'tcx> {
|
||||
pub fn projection_ty_core<V, T>(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
elem: &ProjectionElem<V, T>,
|
||||
mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>,
|
||||
mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>,
|
||||
@ -93,7 +92,9 @@ impl<'tcx> PlaceTy<'tcx> {
|
||||
ty::Slice(..) => self.ty,
|
||||
ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from),
|
||||
ty::Array(inner, size) if from_end => {
|
||||
let size = size.eval_target_usize(tcx, param_env);
|
||||
let size = size
|
||||
.try_to_target_usize(tcx)
|
||||
.expect("expected subslice projection on fixed-size array");
|
||||
let len = size - from - to;
|
||||
Ty::new_array(tcx, *inner, len)
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use rustc_target::abi;
|
||||
|
||||
use crate::infer::canonical::Canonical;
|
||||
use crate::infer::canonical::CanonicalQueryInput;
|
||||
use crate::ty::fast_reject::SimplifiedType;
|
||||
use crate::ty::layout::{TyAndLayout, ValidityRequirement};
|
||||
use crate::ty::{self, GenericArg, GenericArgsRef, Ty, TyCtxt};
|
||||
@ -485,7 +485,7 @@ impl Key for Option<Symbol> {
|
||||
|
||||
/// Canonical query goals correspond to abstract trait operations that
|
||||
/// are not tied to any crate in particular.
|
||||
impl<'tcx, T: Clone> Key for Canonical<'tcx, T> {
|
||||
impl<'tcx, T: Clone> Key for CanonicalQueryInput<'tcx, T> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
|
@ -65,10 +65,11 @@ use crate::query::plumbing::{
|
||||
CyclePlaceholder, DynamicQuery, query_ensure, query_ensure_error_guaranteed, query_get_at,
|
||||
};
|
||||
use crate::traits::query::{
|
||||
CanonicalAliasGoal, CanonicalPredicateGoal, CanonicalTyGoal,
|
||||
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpNormalizeGoal,
|
||||
CanonicalTypeOpProvePredicateGoal, DropckConstraint, DropckOutlivesResult,
|
||||
MethodAutoderefStepsResult, NoSolution, NormalizationResult, OutlivesBound,
|
||||
CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal,
|
||||
CanonicalPredicateGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
|
||||
CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, DropckConstraint,
|
||||
DropckOutlivesResult, MethodAutoderefStepsResult, NoSolution, NormalizationResult,
|
||||
OutlivesBound,
|
||||
};
|
||||
use crate::traits::{
|
||||
CodegenObligationError, DynCompatibilityViolation, EvaluationResult, ImplSource,
|
||||
@ -569,6 +570,7 @@ rustc_queries! {
|
||||
/// either `#[coverage(on)]` or no coverage attribute was found.
|
||||
query coverage_attr_on(key: LocalDefId) -> bool {
|
||||
desc { |tcx| "checking for `#[coverage(..)]` on `{}`", tcx.def_path_str(key) }
|
||||
feedable
|
||||
}
|
||||
|
||||
/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
|
||||
@ -2010,7 +2012,7 @@ rustc_queries! {
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "normalizing `{}`", goal.value.value }
|
||||
desc { "normalizing `{}`", goal.canonical.value.value }
|
||||
}
|
||||
|
||||
/// <div class="warning">
|
||||
@ -2024,7 +2026,7 @@ rustc_queries! {
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "normalizing `{}`", goal.value.value }
|
||||
desc { "normalizing `{}`", goal.canonical.value.value }
|
||||
}
|
||||
|
||||
/// <div class="warning">
|
||||
@ -2038,7 +2040,7 @@ rustc_queries! {
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "normalizing `{}`", goal.value.value }
|
||||
desc { "normalizing `{}`", goal.canonical.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
|
||||
@ -2049,32 +2051,32 @@ rustc_queries! {
|
||||
}
|
||||
|
||||
query implied_outlives_bounds_compat(
|
||||
goal: CanonicalTyGoal<'tcx>
|
||||
goal: CanonicalImpliedOutlivesBoundsGoal<'tcx>
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "computing implied outlives bounds for `{}`", goal.value.value }
|
||||
desc { "computing implied outlives bounds for `{}`", goal.canonical.value.value.ty }
|
||||
}
|
||||
|
||||
query implied_outlives_bounds(
|
||||
goal: CanonicalTyGoal<'tcx>
|
||||
goal: CanonicalImpliedOutlivesBoundsGoal<'tcx>
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "computing implied outlives bounds v2 for `{}`", goal.value.value }
|
||||
desc { "computing implied outlives bounds v2 for `{}`", goal.canonical.value.value.ty }
|
||||
}
|
||||
|
||||
/// Do not call this query directly:
|
||||
/// invoke `DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx)` instead.
|
||||
query dropck_outlives(
|
||||
goal: CanonicalTyGoal<'tcx>
|
||||
goal: CanonicalDropckOutlivesGoal<'tcx>
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "computing dropck types for `{}`", goal.value.value }
|
||||
desc { "computing dropck types for `{}`", goal.canonical.value.value.dropped_ty }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
|
||||
@ -2082,7 +2084,7 @@ rustc_queries! {
|
||||
query evaluate_obligation(
|
||||
goal: CanonicalPredicateGoal<'tcx>
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
desc { "evaluating trait selection obligation `{}`", goal.value.value }
|
||||
desc { "evaluating trait selection obligation `{}`", goal.canonical.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: part of the `Eq` type-op
|
||||
@ -2092,7 +2094,7 @@ rustc_queries! {
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal.value.value }
|
||||
desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal.canonical.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: part of the `ProvePredicate` type-op
|
||||
@ -2102,7 +2104,7 @@ rustc_queries! {
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "evaluating `type_op_prove_predicate` `{:?}`", goal.value.value }
|
||||
desc { "evaluating `type_op_prove_predicate` `{:?}`", goal.canonical.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: part of the `Normalize` type-op
|
||||
@ -2112,7 +2114,7 @@ rustc_queries! {
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "normalizing `{}`", goal.value.value.value }
|
||||
desc { "normalizing `{}`", goal.canonical.value.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: part of the `Normalize` type-op
|
||||
@ -2122,7 +2124,7 @@ rustc_queries! {
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Clause<'tcx>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "normalizing `{:?}`", goal.value.value.value }
|
||||
desc { "normalizing `{:?}`", goal.canonical.value.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: part of the `Normalize` type-op
|
||||
@ -2132,7 +2134,7 @@ rustc_queries! {
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "normalizing `{:?}`", goal.value.value.value }
|
||||
desc { "normalizing `{:?}`", goal.canonical.value.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: part of the `Normalize` type-op
|
||||
@ -2142,7 +2144,7 @@ rustc_queries! {
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "normalizing `{:?}`", goal.value.value.value }
|
||||
desc { "normalizing `{:?}`", goal.canonical.value.value.value }
|
||||
}
|
||||
|
||||
query instantiate_and_check_impossible_predicates(key: (DefId, GenericArgsRef<'tcx>)) -> bool {
|
||||
@ -2163,7 +2165,7 @@ rustc_queries! {
|
||||
query method_autoderef_steps(
|
||||
goal: CanonicalTyGoal<'tcx>
|
||||
) -> MethodAutoderefStepsResult<'tcx> {
|
||||
desc { "computing autoderef types for `{}`", goal.value.value }
|
||||
desc { "computing autoderef types for `{}`", goal.canonical.value.value }
|
||||
}
|
||||
|
||||
query supported_target_features(_: CrateNum) -> &'tcx UnordMap<String, Option<Symbol>> {
|
||||
|
@ -11,16 +11,13 @@ use rustc_span::Span;
|
||||
pub use rustc_type_ir::solve::NoSolution;
|
||||
|
||||
use crate::error::DropCheckOverflow;
|
||||
use crate::infer::canonical::{Canonical, QueryResponse};
|
||||
use crate::infer::canonical::{Canonical, CanonicalQueryInput, QueryResponse};
|
||||
use crate::ty::{self, GenericArg, Ty, TyCtxt};
|
||||
|
||||
pub mod type_op {
|
||||
use std::fmt;
|
||||
|
||||
use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
|
||||
|
||||
use crate::ty::fold::TypeFoldable;
|
||||
use crate::ty::{Predicate, Ty, TyCtxt, UserType};
|
||||
use crate::ty::{Predicate, Ty, UserType};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct AscribeUserType<'tcx> {
|
||||
@ -28,12 +25,6 @@ pub mod type_op {
|
||||
pub user_ty: UserType<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> AscribeUserType<'tcx> {
|
||||
pub fn new(mir_ty: Ty<'tcx>, user_ty: UserType<'tcx>) -> Self {
|
||||
Self { mir_ty, user_ty }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Eq<'tcx> {
|
||||
pub a: Ty<'tcx>,
|
||||
@ -51,46 +42,50 @@ pub mod type_op {
|
||||
pub predicate: Predicate<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ProvePredicate<'tcx> {
|
||||
pub fn new(predicate: Predicate<'tcx>) -> Self {
|
||||
ProvePredicate { predicate }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Normalize<T> {
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
impl<'tcx, T> Normalize<T>
|
||||
where
|
||||
T: fmt::Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
pub fn new(value: T) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct ImpliedOutlivesBounds<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct DropckOutlives<'tcx> {
|
||||
pub dropped_ty: Ty<'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
pub type CanonicalAliasGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>;
|
||||
pub type CanonicalAliasGoal<'tcx> =
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>;
|
||||
|
||||
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
|
||||
pub type CanonicalTyGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
|
||||
|
||||
pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
|
||||
pub type CanonicalPredicateGoal<'tcx> =
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
|
||||
|
||||
pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> =
|
||||
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>;
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>;
|
||||
|
||||
pub type CanonicalTypeOpEqGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Eq<'tcx>>>;
|
||||
pub type CanonicalTypeOpEqGoal<'tcx> =
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::Eq<'tcx>>>;
|
||||
|
||||
pub type CanonicalTypeOpSubtypeGoal<'tcx> =
|
||||
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Subtype<'tcx>>>;
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::Subtype<'tcx>>>;
|
||||
|
||||
pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
|
||||
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ProvePredicate<'tcx>>>;
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::ProvePredicate<'tcx>>>;
|
||||
|
||||
pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
|
||||
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>;
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>;
|
||||
|
||||
pub type CanonicalImpliedOutlivesBoundsGoal<'tcx> =
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::ImpliedOutlivesBounds<'tcx>>>;
|
||||
|
||||
pub type CanonicalDropckOutlivesGoal<'tcx> =
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::DropckOutlives<'tcx>>>;
|
||||
|
||||
#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct DropckOutlivesResult<'tcx> {
|
||||
|
@ -161,9 +161,7 @@ pub enum SelectionCandidate<'tcx> {
|
||||
|
||||
/// Implementation of a `Fn`-family trait by one of the anonymous
|
||||
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
|
||||
FnPointerCandidate {
|
||||
fn_host_effect: ty::Const<'tcx>,
|
||||
},
|
||||
FnPointerCandidate,
|
||||
|
||||
TraitAliasCandidate,
|
||||
|
||||
@ -180,9 +178,6 @@ pub enum SelectionCandidate<'tcx> {
|
||||
BuiltinObjectCandidate,
|
||||
|
||||
BuiltinUnsizeCandidate,
|
||||
|
||||
/// Implementation of `const Destruct`, optionally from a custom `impl const Drop`.
|
||||
ConstDestructCandidate(Option<DefId>),
|
||||
}
|
||||
|
||||
/// The result of trait evaluation. The order is important
|
||||
|
@ -398,133 +398,65 @@ impl<'tcx> Const<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the evaluated constant
|
||||
#[inline]
|
||||
pub fn eval(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
span: Span,
|
||||
) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> {
|
||||
self.eval_valtree(tcx, param_env, span).map_err(|err| {
|
||||
match err {
|
||||
Either::Right(err) => err,
|
||||
Either::Left(_bad_ty) => {
|
||||
// This can happen when we run on ill-typed code.
|
||||
let e = tcx.dcx().span_delayed_bug(
|
||||
span,
|
||||
"`ty::Const::eval` called on a non-valtree-compatible type",
|
||||
);
|
||||
e.into()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Normalizes the constant to a value or an error if possible.
|
||||
#[inline]
|
||||
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
|
||||
match self.eval(tcx, param_env, DUMMY_SP) {
|
||||
pub fn normalize_internal(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
|
||||
match self.eval_valtree(tcx, param_env, DUMMY_SP) {
|
||||
Ok((ty, val)) => Self::new_value(tcx, val, ty),
|
||||
Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into()),
|
||||
Err(ErrorHandled::TooGeneric(_span)) => self,
|
||||
Err(Either::Left(_bad_ty)) => {
|
||||
// This can happen when we run on ill-typed code.
|
||||
Self::new_error(
|
||||
tcx,
|
||||
tcx.dcx()
|
||||
.delayed_bug("`ty::Const::eval` called on a non-valtree-compatible type"),
|
||||
)
|
||||
}
|
||||
Err(Either::Right(ErrorHandled::Reported(r, _span))) => Self::new_error(tcx, r.into()),
|
||||
Err(Either::Right(ErrorHandled::TooGeneric(_span))) => self,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_scalar(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Option<(Ty<'tcx>, Scalar)> {
|
||||
let (ty, val) = self.eval(tcx, param_env, DUMMY_SP).ok()?;
|
||||
let val = val.try_to_scalar()?;
|
||||
Some((ty, val))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
|
||||
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
|
||||
/// contains const generic parameters or pointers).
|
||||
pub fn try_eval_scalar_int(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<(Ty<'tcx>, ScalarInt)> {
|
||||
let (ty, scalar) = self.try_eval_scalar(tcx, param_env)?;
|
||||
let val = scalar.try_to_scalar_int().ok()?;
|
||||
Some((ty, val))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
|
||||
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
|
||||
/// contains const generic parameters or pointers).
|
||||
pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> {
|
||||
let (ty, scalar) = self.try_eval_scalar_int(tcx, param_env)?;
|
||||
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
|
||||
// if `ty` does not depend on generic parameters, use an empty param_env
|
||||
Some(scalar.to_bits(size))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
|
||||
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 {
|
||||
self.try_eval_bits(tcx, param_env)
|
||||
.unwrap_or_else(|| bug!("failed to evalate {:#?} to bits", self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_target_usize(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<u64> {
|
||||
let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?;
|
||||
Some(scalar.to_target_usize(tcx))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
|
||||
let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?;
|
||||
scalar.try_into().ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
|
||||
pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
|
||||
self.try_eval_target_usize(tcx, param_env)
|
||||
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
|
||||
}
|
||||
|
||||
/// Panics if self.kind != ty::ConstKind::Value
|
||||
pub fn to_valtree(self) -> ty::ValTree<'tcx> {
|
||||
pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) {
|
||||
match self.kind() {
|
||||
ty::ConstKind::Value(_, valtree) => valtree,
|
||||
ty::ConstKind::Value(ty, valtree) => (valtree, ty),
|
||||
_ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to convert to a `ValTree`
|
||||
pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> {
|
||||
pub fn try_to_valtree(self) -> Option<(ty::ValTree<'tcx>, Ty<'tcx>)> {
|
||||
match self.kind() {
|
||||
ty::ConstKind::Value(_, valtree) => Some(valtree),
|
||||
ty::ConstKind::Value(ty, valtree) => Some((valtree, ty)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_scalar(self) -> Option<Scalar> {
|
||||
self.try_to_valtree()?.try_to_scalar()
|
||||
pub fn try_to_scalar(self) -> Option<(Scalar, Ty<'tcx>)> {
|
||||
let (valtree, ty) = self.try_to_valtree()?;
|
||||
Some((valtree.try_to_scalar()?, ty))
|
||||
}
|
||||
|
||||
pub fn try_to_bool(self) -> Option<bool> {
|
||||
self.try_to_valtree()?.try_to_scalar_int()?.try_to_bool().ok()
|
||||
self.try_to_valtree()?.0.try_to_scalar_int()?.try_to_bool().ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_valtree()?.try_to_target_usize(tcx)
|
||||
self.try_to_valtree()?.0.try_to_target_usize(tcx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
|
||||
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
|
||||
/// contains const generic parameters or pointers).
|
||||
pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> {
|
||||
let (scalar, ty) = self.try_to_scalar()?;
|
||||
let scalar = scalar.try_to_scalar_int().ok()?;
|
||||
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
|
||||
// if `ty` does not depend on generic parameters, use an empty param_env
|
||||
Some(scalar.to_bits(size))
|
||||
}
|
||||
|
||||
pub fn is_ct_infer(self) -> bool {
|
||||
|
@ -85,7 +85,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
|
||||
match self {
|
||||
Self::False => Ok(false),
|
||||
Self::True => Ok(true),
|
||||
Self::ConstIsZero(const_) => match const_.try_eval_target_usize(tcx, param_env) {
|
||||
Self::ConstIsZero(const_) => match const_.try_to_target_usize(tcx) {
|
||||
None | Some(0) => Ok(true),
|
||||
Some(1..) => Ok(false),
|
||||
},
|
||||
|
@ -397,7 +397,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
|
||||
}
|
||||
}
|
||||
ty::Array(inner, len) if tcx.features().transmute_generic_consts => {
|
||||
let len_eval = len.try_eval_target_usize(tcx, param_env);
|
||||
let len_eval = len.try_to_target_usize(tcx);
|
||||
if len_eval == Some(0) {
|
||||
return Ok(SizeSkeleton::Known(Size::from_bytes(0), None));
|
||||
}
|
||||
|
@ -1956,7 +1956,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||
define_scoped_cx!(self);
|
||||
|
||||
match constness {
|
||||
ty::BoundConstness::NotConst => {}
|
||||
ty::BoundConstness::Const => {
|
||||
p!("const ");
|
||||
}
|
||||
@ -2948,7 +2947,10 @@ impl<'tcx> ty::TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct TraitPredPrintWithBoundConstness<'tcx>(ty::TraitPredicate<'tcx>, ty::BoundConstness);
|
||||
pub struct TraitPredPrintWithBoundConstness<'tcx>(
|
||||
ty::TraitPredicate<'tcx>,
|
||||
Option<ty::BoundConstness>,
|
||||
);
|
||||
|
||||
impl<'tcx> fmt::Debug for TraitPredPrintWithBoundConstness<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
@ -2966,7 +2968,7 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> {
|
||||
|
||||
fn print_with_bound_constness(
|
||||
self,
|
||||
constness: ty::BoundConstness,
|
||||
constness: Option<ty::BoundConstness>,
|
||||
) -> ty::Binder<'tcx, TraitPredPrintWithBoundConstness<'tcx>> {
|
||||
self.map_bound(|trait_pred| TraitPredPrintWithBoundConstness(trait_pred, constness))
|
||||
}
|
||||
@ -3206,7 +3208,9 @@ define_print_and_forward_display! {
|
||||
|
||||
TraitPredPrintWithBoundConstness<'tcx> {
|
||||
p!(print(self.0.trait_ref.self_ty()), ": ");
|
||||
p!(pretty_print_bound_constness(self.1));
|
||||
if let Some(constness) = self.1 {
|
||||
p!(pretty_print_bound_constness(constness));
|
||||
}
|
||||
if let ty::PredicatePolarity::Negative = self.0.polarity {
|
||||
p!("!");
|
||||
}
|
||||
|
@ -1117,7 +1117,12 @@ impl<'tcx> Ty<'tcx> {
|
||||
// The way we evaluate the `N` in `[T; N]` here only works since we use
|
||||
// `simd_size_and_type` post-monomorphization. It will probably start to ICE
|
||||
// if we use it in generic code. See the `simd-array-trait` ui test.
|
||||
(f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty)
|
||||
(
|
||||
f0_len
|
||||
.try_to_target_usize(tcx)
|
||||
.expect("expected SIMD field to have definite array size"),
|
||||
*f0_elem_ty,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -907,24 +907,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs generic args for an item, optionally appending a const effect param type
|
||||
pub fn with_opt_host_effect_param(
|
||||
self,
|
||||
caller_def_id: LocalDefId,
|
||||
callee_def_id: DefId,
|
||||
args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
|
||||
) -> ty::GenericArgsRef<'tcx> {
|
||||
let generics = self.generics_of(callee_def_id);
|
||||
assert_eq!(generics.parent, None);
|
||||
|
||||
let opt_const_param = generics
|
||||
.host_effect_index
|
||||
.is_some()
|
||||
.then(|| ty::GenericArg::from(self.expected_host_effect_param_for_body(caller_def_id)));
|
||||
|
||||
self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param))
|
||||
}
|
||||
|
||||
/// Expand any [weak alias types][weak] contained within the given `value`.
|
||||
///
|
||||
/// This should be used over other normalization routines in situations where
|
||||
|
@ -454,12 +454,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
};
|
||||
|
||||
let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
|
||||
let method = trait_method(
|
||||
self.tcx,
|
||||
eq_def_id,
|
||||
sym::eq,
|
||||
self.tcx.with_opt_host_effect_param(self.def_id, eq_def_id, [compare_ty, compare_ty]),
|
||||
);
|
||||
let method = trait_method(self.tcx, eq_def_id, sym::eq, [compare_ty, compare_ty]);
|
||||
|
||||
let bool_ty = self.tcx.types.bool;
|
||||
let eq_result = self.temp(bool_ty, source_info.span);
|
||||
|
@ -43,7 +43,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
struct ConstToPat<'tcx> {
|
||||
id: hir::HirId,
|
||||
span: Span,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
||||
@ -62,7 +61,6 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
) -> Self {
|
||||
trace!(?pat_ctxt.typeck_results.hir_owner);
|
||||
ConstToPat {
|
||||
id,
|
||||
span,
|
||||
infcx,
|
||||
param_env: pat_ctxt.param_env,
|
||||
@ -149,15 +147,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
tcx,
|
||||
ObligationCause::dummy(),
|
||||
self.param_env,
|
||||
ty::TraitRef::new_from_args(
|
||||
tcx,
|
||||
partial_eq_trait_id,
|
||||
tcx.with_opt_host_effect_param(
|
||||
tcx.hir().enclosing_body_owner(self.id),
|
||||
partial_eq_trait_id,
|
||||
[ty, ty],
|
||||
),
|
||||
),
|
||||
ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]),
|
||||
);
|
||||
|
||||
// This *could* accept a type that isn't actually `PartialEq`, because region bounds get
|
||||
|
@ -863,7 +863,7 @@ where
|
||||
ty::Adt(def, args) => self.open_drop_for_adt(*def, args),
|
||||
ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
|
||||
ty::Array(ety, size) => {
|
||||
let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env());
|
||||
let size = size.try_to_target_usize(self.tcx());
|
||||
self.open_drop_for_array(*ety, size)
|
||||
}
|
||||
ty::Slice(ety) => self.drop_loop_pair(*ety),
|
||||
|
@ -18,18 +18,12 @@ struct MoveDataBuilder<'a, 'tcx, F> {
|
||||
body: &'a Body<'tcx>,
|
||||
loc: Location,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
data: MoveData<'tcx>,
|
||||
filter: F,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
||||
fn new(
|
||||
body: &'a Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
filter: F,
|
||||
) -> Self {
|
||||
fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, filter: F) -> Self {
|
||||
let mut move_paths = IndexVec::new();
|
||||
let mut path_map = IndexVec::new();
|
||||
let mut init_path_map = IndexVec::new();
|
||||
@ -59,7 +53,6 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
||||
body,
|
||||
loc: Location::START,
|
||||
tcx,
|
||||
param_env,
|
||||
data: MoveData {
|
||||
moves: IndexVec::new(),
|
||||
loc_map: LocationMap::new(body),
|
||||
@ -308,10 +301,9 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
||||
pub(super) fn gather_moves<'tcx>(
|
||||
body: &Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
filter: impl Fn(Ty<'tcx>) -> bool,
|
||||
) -> MoveData<'tcx> {
|
||||
let mut builder = MoveDataBuilder::new(body, tcx, param_env, filter);
|
||||
let mut builder = MoveDataBuilder::new(body, tcx, filter);
|
||||
|
||||
builder.gather_args();
|
||||
|
||||
@ -550,7 +542,9 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
||||
};
|
||||
let base_ty = base_place.ty(self.body, self.tcx).ty;
|
||||
let len: u64 = match base_ty.kind() {
|
||||
ty::Array(_, size) => size.eval_target_usize(self.tcx, self.param_env),
|
||||
ty::Array(_, size) => size
|
||||
.try_to_target_usize(self.tcx)
|
||||
.expect("expected subslice projection on fixed-size array"),
|
||||
_ => bug!("from_end: false slice pattern of non-array type"),
|
||||
};
|
||||
for offset in from..to {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user