Auto merge of #3980 - rust-lang:rustup-2024-10-20, r=RalfJung
Automatic Rustup
This commit is contained in:
commit
45a9a7ca5a
675 changed files with 10414 additions and 4850 deletions
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>
|
||||
|
|
|
|||
61
Cargo.lock
61
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"
|
||||
|
|
@ -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",
|
||||
|
|
@ -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",
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -123,7 +123,6 @@ Stabilized APIs
|
|||
These APIs are now stable in const contexts:
|
||||
|
||||
- [`std::task::Waker::from_raw`](https://doc.rust-lang.org/nightly/std/task/struct.Waker.html#method.from_raw)
|
||||
- [`std::task::Waker::waker`](https://doc.rust-lang.org/nightly/std/task/struct.Waker.html#method.from_raw)
|
||||
- [`std::task::Context::from_waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.from_waker)
|
||||
- [`std::task::Context::waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.waker)
|
||||
- [`$integer::from_str_radix`](https://doc.rust-lang.org/nightly/std/primitive.u32.html#method.from_str_radix)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,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 +54,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 +519,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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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, .. }) => {
|
||||
|
|
|
|||
|
|
@ -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}"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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: {}",
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -52,7 +52,7 @@ impl<'tcx> Bounds<'tcx> {
|
|||
span: Span,
|
||||
polarity: ty::PredicatePolarity,
|
||||
constness: ty::BoundConstness,
|
||||
only_self_bounds: OnlySelfBounds,
|
||||
predicate_filter: PredicateFilter,
|
||||
) {
|
||||
let clause = (
|
||||
bound_trait_ref
|
||||
|
|
@ -72,9 +72,18 @@ 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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -270,7 +270,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
bound_pred.bounds.iter(),
|
||||
&mut bounds,
|
||||
bound_vars,
|
||||
OnlySelfBounds(false),
|
||||
PredicateFilter::All,
|
||||
);
|
||||
predicates.extend(bounds.clauses(tcx));
|
||||
effects_min_tys.extend(bounds.effects_min_tys());
|
||||
|
|
@ -825,20 +825,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) {
|
||||
|
|
@ -850,31 +836,13 @@ impl<'tcx> ItemCtxt<'tcx> {
|
|||
let bound_vars = self.tcx.late_bound_vars(predicate.hir_id);
|
||||
self.lowerer().lower_poly_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.iter(),
|
||||
&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.
|
||||
|
|
@ -150,11 +148,25 @@ impl<'tcx> dyn HirTyLowerer<'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 {
|
||||
|
|
@ -179,7 +191,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
polarity,
|
||||
param_ty,
|
||||
bounds,
|
||||
only_self_bounds,
|
||||
predicate_filter,
|
||||
);
|
||||
}
|
||||
hir::GenericBound::Outlives(lifetime) => {
|
||||
|
|
@ -213,37 +225,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
&self,
|
||||
param_ty: Ty<'tcx>,
|
||||
hir_bounds: &[hir::GenericBound<'tcx>],
|
||||
filter: PredicateFilter,
|
||||
predicate_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
|
||||
}
|
||||
}
|
||||
}),
|
||||
hir_bounds.iter(),
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
only_self_bounds,
|
||||
predicate_filter,
|
||||
);
|
||||
debug!(?bounds);
|
||||
|
||||
|
|
@ -267,7 +258,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 +435,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_poly_bounds(
|
||||
param_ty,
|
||||
hir_bounds.iter(),
|
||||
bounds,
|
||||
projection_ty.bound_vars(),
|
||||
predicate_filter,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -516,7 +509,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> + '_ {
|
||||
|
|
@ -55,9 +55,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -683,7 +656,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
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 ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = 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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)`
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -983,15 +985,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 +1003,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()
|
||||
}
|
||||
|
|
@ -156,7 +156,7 @@ declare_lint! {
|
|||
///
|
||||
/// ```rust
|
||||
/// #![forbid(warnings)]
|
||||
/// #![deny(bad_style)]
|
||||
/// #![warn(bad_style)]
|
||||
///
|
||||
/// fn main() {}
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -51,11 +51,20 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
|
|||
// This will filter to functions with `extern "C-unwind"` ABIs, for
|
||||
// example.
|
||||
for block in body.basic_blocks.as_mut() {
|
||||
let Some(terminator) = &mut block.terminator else { continue };
|
||||
let span = terminator.source_info.span;
|
||||
|
||||
// If we see an `UnwindResume` terminator inside a function that cannot unwind, we need
|
||||
// to replace it with `UnwindTerminate`.
|
||||
if let TerminatorKind::UnwindResume = &terminator.kind
|
||||
&& !body_can_unwind
|
||||
{
|
||||
terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi);
|
||||
}
|
||||
|
||||
if block.is_cleanup {
|
||||
continue;
|
||||
}
|
||||
let Some(terminator) = &block.terminator else { continue };
|
||||
let span = terminator.source_info.span;
|
||||
|
||||
let call_can_unwind = match &terminator.kind {
|
||||
TerminatorKind::Call { func, .. } => {
|
||||
|
|
@ -87,14 +96,18 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
|
|||
if !call_can_unwind {
|
||||
// If this function call can't unwind, then there's no need for it
|
||||
// to have a landing pad. This means that we can remove any cleanup
|
||||
// registered for it.
|
||||
// registered for it (and turn it into `UnwindAction::Unreachable`).
|
||||
let cleanup = block.terminator_mut().unwind_mut().unwrap();
|
||||
*cleanup = UnwindAction::Unreachable;
|
||||
} else if !body_can_unwind {
|
||||
} else if !body_can_unwind
|
||||
&& matches!(terminator.unwind(), Some(UnwindAction::Continue))
|
||||
{
|
||||
// Otherwise if this function can unwind, then if the outer function
|
||||
// can also unwind there's nothing to do. If the outer function
|
||||
// can't unwind, however, we need to change the landing pad for this
|
||||
// function call to one that aborts.
|
||||
// can't unwind, however, we need to ensure that any `UnwindAction::Continue`
|
||||
// is replaced with terminate. For those with `UnwindAction::Cleanup`,
|
||||
// cleanup will still happen, and terminate will happen afterwards handled by
|
||||
// the `UnwindResume` -> `UnwindTerminate` terminator replacement.
|
||||
let cleanup = block.terminator_mut().unwind_mut().unwrap();
|
||||
*cleanup = UnwindAction::Terminate(UnwindTerminateReason::Abi);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
|
|||
|
||||
// Inherited from the by-ref coroutine.
|
||||
body_def.codegen_fn_attrs(tcx.codegen_fn_attrs(coroutine_def_id).clone());
|
||||
body_def.coverage_attr_on(tcx.coverage_attr_on(coroutine_def_id));
|
||||
body_def.constness(tcx.constness(coroutine_def_id));
|
||||
body_def.coroutine_kind(tcx.coroutine_kind(coroutine_def_id));
|
||||
body_def.def_ident_span(tcx.def_ident_span(coroutine_def_id));
|
||||
|
|
|
|||
|
|
@ -524,6 +524,11 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
|
|||
// FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
|
||||
// to HIR for it.
|
||||
|
||||
// HACK: For synthetic MIR bodies (async closures), use the def id of the HIR body.
|
||||
if tcx.is_synthetic_mir(def_id) {
|
||||
return extract_hir_info(tcx, tcx.local_parent(def_id));
|
||||
}
|
||||
|
||||
let hir_node = tcx.hir_node_by_def_id(def_id);
|
||||
let fn_body_id = hir_node.body_id().expect("HIR node is a function with body");
|
||||
let hir_body = tcx.hir().body(fn_body_id);
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
F: FnOnce(&mut Self) -> InterpResult<'tcx, T>,
|
||||
{
|
||||
f(self)
|
||||
.map_err(|err| {
|
||||
.map_err_info(|err| {
|
||||
trace!("InterpCx operation failed: {:?}", err);
|
||||
// Some errors shouldn't come up because creating them causes
|
||||
// an allocation, which we should avoid. When that happens,
|
||||
|
|
|
|||
|
|
@ -83,8 +83,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
|
||||
let (max_universe, variables) = canonicalizer.finalize();
|
||||
|
||||
let defining_opaque_types = delegate.defining_opaque_types();
|
||||
Canonical { defining_opaque_types, max_universe, variables, value }
|
||||
Canonical { max_universe, variables, value }
|
||||
}
|
||||
|
||||
fn get_or_insert_bound_var(
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ use rustc_type_ir::fold::TypeFoldable;
|
|||
use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode};
|
||||
use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
|
||||
|
||||
pub trait SolverDelegate:
|
||||
Deref<Target: InferCtxtLike<Interner = <Self as SolverDelegate>::Interner>> + Sized
|
||||
{
|
||||
pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Sized {
|
||||
type Infcx: InferCtxtLike<Interner = <Self as SolverDelegate>::Interner>;
|
||||
type Interner: Interner;
|
||||
fn cx(&self) -> Self::Interner {
|
||||
(**self).cx()
|
||||
|
|
@ -17,7 +16,7 @@ pub trait SolverDelegate:
|
|||
fn build_with_canonical<V>(
|
||||
cx: Self::Interner,
|
||||
solver_mode: SolverMode,
|
||||
canonical: &ty::Canonical<Self::Interner, V>,
|
||||
canonical: &ty::CanonicalQueryInput<Self::Interner, V>,
|
||||
) -> (Self, V, ty::CanonicalVarValues<Self::Interner>)
|
||||
where
|
||||
V: TypeFoldable<Self::Interner>;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ where
|
|||
(goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate));
|
||||
|
||||
let mut orig_values = Default::default();
|
||||
let canonical_goal = Canonicalizer::canonicalize(
|
||||
let canonical = Canonicalizer::canonicalize(
|
||||
self.delegate,
|
||||
CanonicalizeMode::Input,
|
||||
&mut orig_values,
|
||||
|
|
@ -71,7 +71,11 @@ where
|
|||
.mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }),
|
||||
},
|
||||
);
|
||||
(orig_values, canonical_goal)
|
||||
let query_input = ty::CanonicalQueryInput {
|
||||
canonical,
|
||||
defining_opaque_types: self.delegate.defining_opaque_types(),
|
||||
};
|
||||
(orig_values, query_input)
|
||||
}
|
||||
|
||||
/// To return the constraints of a canonical query to the caller, we canonicalize:
|
||||
|
|
|
|||
|
|
@ -283,11 +283,11 @@ where
|
|||
|
||||
let mut ecx = EvalCtxt {
|
||||
delegate,
|
||||
variables: canonical_input.variables,
|
||||
variables: canonical_input.canonical.variables,
|
||||
var_values,
|
||||
is_normalizes_to_goal: false,
|
||||
predefined_opaques_in_body: input.predefined_opaques_in_body,
|
||||
max_input_universe: canonical_input.max_universe,
|
||||
max_input_universe: canonical_input.canonical.max_universe,
|
||||
search_graph,
|
||||
nested_goals: NestedGoals::new(),
|
||||
tainted: Ok(()),
|
||||
|
|
|
|||
|
|
@ -313,6 +313,5 @@ fn response_no_constraints_raw<I: Interner>(
|
|||
external_constraints: cx.mk_external_constraints(ExternalConstraintsData::default()),
|
||||
certainty,
|
||||
},
|
||||
defining_opaque_types: Default::default(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,14 +96,19 @@ where
|
|||
}
|
||||
|
||||
fn step_is_coinductive(cx: I, input: CanonicalInput<I>) -> bool {
|
||||
input.value.goal.predicate.is_coinductive(cx)
|
||||
input.canonical.value.goal.predicate.is_coinductive(cx)
|
||||
}
|
||||
}
|
||||
|
||||
fn response_no_constraints<I: Interner>(
|
||||
cx: I,
|
||||
goal: CanonicalInput<I>,
|
||||
input: CanonicalInput<I>,
|
||||
certainty: Certainty,
|
||||
) -> QueryResult<I> {
|
||||
Ok(super::response_no_constraints_raw(cx, goal.max_universe, goal.variables, certainty))
|
||||
Ok(super::response_no_constraints_raw(
|
||||
cx,
|
||||
input.canonical.max_universe,
|
||||
input.canonical.variables,
|
||||
certainty,
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -785,7 +785,8 @@ where
|
|||
let mut responses = vec![];
|
||||
// If the principal def ids match (or are both none), then we're not doing
|
||||
// trait upcasting. We're just removing auto traits (or shortening the lifetime).
|
||||
if a_data.principal_def_id() == b_data.principal_def_id() {
|
||||
let b_principal_def_id = b_data.principal_def_id();
|
||||
if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
|
||||
responses.extend(self.consider_builtin_upcast_to_principal(
|
||||
goal,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
|
|
|
|||
|
|
@ -184,11 +184,11 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
|
|||
|
||||
// If the extern crate isn't in the extern prelude,
|
||||
// there is no way it can be written as a `use`.
|
||||
if !self
|
||||
if self
|
||||
.r
|
||||
.extern_prelude
|
||||
.get(&extern_crate.ident)
|
||||
.is_some_and(|entry| !entry.introduced_by_item)
|
||||
.is_none_or(|entry| entry.introduced_by_item)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4011,6 +4011,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
let instead = res.is_some();
|
||||
let suggestion = if let Some((start, end)) = this.diag_metadata.in_range
|
||||
&& path[0].ident.span.lo() == end.span.lo()
|
||||
&& !matches!(start.kind, ExprKind::Lit(_))
|
||||
{
|
||||
let mut sugg = ".";
|
||||
let mut span = start.span.between(end.span);
|
||||
|
|
|
|||
|
|
@ -2514,6 +2514,13 @@ fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'stati
|
|||
add_link_args_iter(link_args, flavor, args.iter().copied().map(Cow::Borrowed))
|
||||
}
|
||||
|
||||
impl TargetOptions {
|
||||
pub fn supports_comdat(&self) -> bool {
|
||||
// XCOFF and MachO don't support COMDAT.
|
||||
!self.is_like_aix && !self.is_like_osx
|
||||
}
|
||||
}
|
||||
|
||||
impl TargetOptions {
|
||||
fn link_args(flavor: LinkerFlavor, args: &[&'static str]) -> LinkArgs {
|
||||
let mut link_args = LinkArgs::new();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ pub(crate) fn target() -> Target {
|
|||
| SanitizerSet::LEAK
|
||||
| SanitizerSet::MEMORY
|
||||
| SanitizerSet::THREAD,
|
||||
supports_xray: true,
|
||||
direct_access_external_data: Some(false),
|
||||
..base::linux_gnu::opts()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ pub(crate) fn target() -> Target {
|
|||
| SanitizerSet::LEAK
|
||||
| SanitizerSet::MEMORY
|
||||
| SanitizerSet::THREAD,
|
||||
supports_xray: true,
|
||||
direct_access_external_data: Some(false),
|
||||
..base::linux_musl::opts()
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{SanitizerSet, Target, TargetOptions, base};
|
||||
use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -13,6 +13,7 @@ pub(crate) fn target() -> Target {
|
|||
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
|
||||
arch: "loongarch64".into(),
|
||||
options: TargetOptions {
|
||||
code_model: Some(CodeModel::Medium),
|
||||
cpu: "generic".into(),
|
||||
features: "+f,+d".into(),
|
||||
llvm_abiname: "lp64d".into(),
|
||||
|
|
@ -22,6 +23,8 @@ pub(crate) fn target() -> Target {
|
|||
| SanitizerSet::LEAK
|
||||
| SanitizerSet::MEMORY
|
||||
| SanitizerSet::THREAD,
|
||||
supports_xray: true,
|
||||
direct_access_external_data: Some(false),
|
||||
..base::linux_ohos::opts()
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1277,19 +1277,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let normalized_term =
|
||||
ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
|
||||
|
||||
let is_normalized_term_expected = !matches!(
|
||||
obligation.cause.code().peel_derives(),
|
||||
ObligationCauseCode::WhereClause(..)
|
||||
| ObligationCauseCode::WhereClauseInExpr(..)
|
||||
| ObligationCauseCode::Coercion { .. }
|
||||
);
|
||||
|
||||
let (expected, actual) = if is_normalized_term_expected {
|
||||
(normalized_term, data.term)
|
||||
} else {
|
||||
(data.term, normalized_term)
|
||||
};
|
||||
|
||||
// constrain inference variables a bit more to nested obligations from normalize so
|
||||
// we can have more helpful errors.
|
||||
//
|
||||
|
|
@ -1298,12 +1285,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let _ = ocx.select_where_possible();
|
||||
|
||||
if let Err(new_err) =
|
||||
ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
|
||||
ocx.eq(&obligation.cause, obligation.param_env, data.term, normalized_term)
|
||||
{
|
||||
(
|
||||
Some((
|
||||
data.projection_term,
|
||||
is_normalized_term_expected,
|
||||
false,
|
||||
self.resolve_vars_if_possible(normalized_term),
|
||||
data.term,
|
||||
)),
|
||||
|
|
@ -1444,12 +1431,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
&mut diag,
|
||||
&obligation.cause,
|
||||
secondary_span,
|
||||
values.map(|(_, is_normalized_ty_expected, normalized_ty, expected_ty)| {
|
||||
infer::ValuePairs::Terms(ExpectedFound::new(
|
||||
is_normalized_ty_expected,
|
||||
normalized_ty,
|
||||
expected_ty,
|
||||
))
|
||||
values.map(|(_, _, normalized_ty, expected_ty)| {
|
||||
infer::ValuePairs::Terms(ExpectedFound::new(true, expected_ty, normalized_ty))
|
||||
}),
|
||||
err,
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ use rustc_hir::lang_items::LangItem;
|
|||
pub use rustc_infer::infer::*;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::arena::ArenaAllocatable;
|
||||
use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
|
||||
use rustc_middle::infer::canonical::{
|
||||
Canonical, CanonicalQueryInput, CanonicalQueryResponse, QueryResponse,
|
||||
};
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
|
@ -132,7 +134,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
/// `K: TypeFoldable<TyCtxt<'tcx>>`.)
|
||||
fn enter_canonical_trait_query<K, R>(
|
||||
self,
|
||||
canonical_key: &Canonical<'tcx, K>,
|
||||
canonical_key: &CanonicalQueryInput<'tcx, K>,
|
||||
operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
|
||||
use rustc_infer::infer::canonical::{
|
||||
Canonical, CanonicalExt as _, CanonicalVarInfo, CanonicalVarValues,
|
||||
Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
|
||||
};
|
||||
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
|
|
@ -36,6 +36,7 @@ impl<'tcx> Deref for SolverDelegate<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<'tcx> {
|
||||
type Infcx = InferCtxt<'tcx>;
|
||||
type Interner = TyCtxt<'tcx>;
|
||||
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
|
|
@ -47,7 +48,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
fn build_with_canonical<V>(
|
||||
interner: TyCtxt<'tcx>,
|
||||
solver_mode: SolverMode,
|
||||
canonical: &Canonical<'tcx, V>,
|
||||
canonical: &CanonicalQueryInput<'tcx, V>,
|
||||
) -> (Self, V, CanonicalVarValues<'tcx>)
|
||||
where
|
||||
V: TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints};
|
||||
use rustc_middle::span_bug;
|
||||
|
|
@ -54,11 +55,12 @@ fn implied_outlives_bounds<'a, 'tcx>(
|
|||
assert!(!ty.has_non_region_infer());
|
||||
|
||||
let mut canonical_var_values = OriginalQueryValues::default();
|
||||
let canonical_ty = infcx.canonicalize_query(param_env.and(ty), &mut canonical_var_values);
|
||||
let input = ImpliedOutlivesBounds { ty };
|
||||
let canonical = infcx.canonicalize_query(param_env.and(input), &mut canonical_var_values);
|
||||
let implied_bounds_result = if compat {
|
||||
infcx.tcx.implied_outlives_bounds_compat(canonical_ty)
|
||||
infcx.tcx.implied_outlives_bounds_compat(canonical)
|
||||
} else {
|
||||
infcx.tcx.implied_outlives_bounds(canonical_ty)
|
||||
infcx.tcx.implied_outlives_bounds(canonical)
|
||||
};
|
||||
let Ok(canonical_result) = implied_bounds_result else {
|
||||
return vec![];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_infer::traits::query::type_op::DropckOutlives;
|
||||
use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
|
||||
use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
|
|
@ -88,10 +89,10 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
|
||||
pub fn compute_dropck_outlives_inner<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
goal: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>,
|
||||
) -> Result<DropckOutlivesResult<'tcx>, NoSolution> {
|
||||
let tcx = ocx.infcx.tcx;
|
||||
let ParamEnvAnd { param_env, value: for_ty } = goal;
|
||||
let ParamEnvAnd { param_env, value: DropckOutlives { dropped_ty } } = goal;
|
||||
|
||||
let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
|
||||
|
||||
|
|
@ -99,7 +100,7 @@ pub fn compute_dropck_outlives_inner<'tcx>(
|
|||
// something from the stack and invoke
|
||||
// `dtorck_constraint_for_ty_inner`. This may produce new types that
|
||||
// have to be pushed on the stack. This continues until we have explored
|
||||
// all the reachable types from the type `for_ty`.
|
||||
// all the reachable types from the type `dropped_ty`.
|
||||
//
|
||||
// Example: Imagine that we have the following code:
|
||||
//
|
||||
|
|
@ -129,7 +130,7 @@ pub fn compute_dropck_outlives_inner<'tcx>(
|
|||
// lead to us trying to push `A` a second time -- to prevent
|
||||
// infinite recursion, we notice that `A` was already pushed
|
||||
// once and stop.
|
||||
let mut ty_stack = vec![(for_ty, 0)];
|
||||
let mut ty_stack = vec![(dropped_ty, 0)];
|
||||
|
||||
// Set used to detect infinite recursion.
|
||||
let mut ty_set = FxHashSet::default();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserArgs, UserSelfTy, User
|
|||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
|
||||
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
||||
impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
|
||||
|
|
@ -22,7 +22,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
|
|||
|
||||
fn perform_query(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
|
||||
tcx.type_op_ascribe_user_type(canonicalized)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::canonical::CanonicalQueryInput;
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_infer::traits::query::OutlivesBound;
|
||||
use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
|
||||
use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
|
||||
use rustc_middle::infer::canonical::CanonicalQueryResponse;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
|
||||
|
|
@ -14,11 +14,6 @@ use tracing::debug;
|
|||
use crate::traits::query::NoSolution;
|
||||
use crate::traits::{ObligationCtxt, wf};
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct ImpliedOutlivesBounds<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
|
||||
type QueryResponse = Vec<OutlivesBound<'tcx>>;
|
||||
|
||||
|
|
@ -38,16 +33,8 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
|
|||
|
||||
fn perform_query(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
|
||||
// FIXME this `unchecked_map` is only necessary because the
|
||||
// query is defined as taking a `ParamEnvAnd<Ty>`; it should
|
||||
// take an `ImpliedOutlivesBounds` instead
|
||||
let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| {
|
||||
let ImpliedOutlivesBounds { ty } = value;
|
||||
param_env.and(ty)
|
||||
});
|
||||
|
||||
if tcx.sess.opts.unstable_opts.no_implied_bounds_compat {
|
||||
tcx.implied_outlives_bounds(canonicalized)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_infer::infer::canonical::Certainty;
|
||||
use rustc_infer::traits::PredicateObligations;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
|
|
@ -9,7 +8,8 @@ use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
|
|||
use rustc_span::Span;
|
||||
|
||||
use crate::infer::canonical::{
|
||||
Canonical, CanonicalQueryResponse, OriginalQueryValues, QueryRegionConstraints,
|
||||
CanonicalQueryInput, CanonicalQueryResponse, Certainty, OriginalQueryValues,
|
||||
QueryRegionConstraints,
|
||||
};
|
||||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits::{ObligationCause, ObligationCtxt};
|
||||
|
|
@ -80,7 +80,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
|
|||
/// not captured in the return value.
|
||||
fn perform_query(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution>;
|
||||
|
||||
/// In the new trait solver, we already do caching in the solver itself,
|
||||
|
|
@ -102,7 +102,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
|
|||
) -> Result<
|
||||
(
|
||||
Self::QueryResponse,
|
||||
Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
|
||||
Option<CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>>,
|
||||
PredicateObligations<'tcx>,
|
||||
Certainty,
|
||||
),
|
||||
|
|
@ -135,7 +135,7 @@ where
|
|||
Q: QueryTypeOp<'tcx>,
|
||||
{
|
||||
type Output = Q::QueryResponse;
|
||||
type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>;
|
||||
type ErrorInfo = CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Q>>;
|
||||
|
||||
fn fully_perform(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ pub use rustc_middle::traits::query::type_op::Normalize;
|
|||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
||||
|
||||
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
|
||||
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
||||
impl<'tcx, T> super::QueryTypeOp<'tcx> for Normalize<T>
|
||||
|
|
@ -21,7 +21,7 @@ where
|
|||
|
||||
fn perform_query(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
|
||||
T::type_op_method(tcx, canonicalized)
|
||||
}
|
||||
|
|
@ -40,14 +40,14 @@ pub trait Normalizable<'tcx>:
|
|||
{
|
||||
fn type_op_method(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution>;
|
||||
}
|
||||
|
||||
impl<'tcx> Normalizable<'tcx> for Ty<'tcx> {
|
||||
fn type_op_method(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
|
||||
tcx.type_op_normalize_ty(canonicalized)
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ impl<'tcx> Normalizable<'tcx> for Ty<'tcx> {
|
|||
impl<'tcx> Normalizable<'tcx> for ty::Clause<'tcx> {
|
||||
fn type_op_method(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
|
||||
tcx.type_op_normalize_clause(canonicalized)
|
||||
}
|
||||
|
|
@ -65,7 +65,7 @@ impl<'tcx> Normalizable<'tcx> for ty::Clause<'tcx> {
|
|||
impl<'tcx> Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
|
||||
fn type_op_method(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
|
||||
tcx.type_op_normalize_poly_fn_sig(canonicalized)
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ impl<'tcx> Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
|
|||
impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> {
|
||||
fn type_op_method(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
|
||||
tcx.type_op_normalize_fn_sig(canonicalized)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,12 @@
|
|||
use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
|
||||
use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution};
|
||||
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
|
||||
|
||||
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
|
||||
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
use crate::traits::query::dropck_outlives::{
|
||||
compute_dropck_outlives_inner, trivial_dropck_outlives,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct DropckOutlives<'tcx> {
|
||||
dropped_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> DropckOutlives<'tcx> {
|
||||
pub fn new(dropped_ty: Ty<'tcx>) -> Self {
|
||||
DropckOutlives { dropped_ty }
|
||||
}
|
||||
}
|
||||
use crate::traits::query::type_op::DropckOutlives;
|
||||
|
||||
impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
|
||||
type QueryResponse = DropckOutlivesResult<'tcx>;
|
||||
|
|
@ -31,16 +20,8 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
|
|||
|
||||
fn perform_query(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
|
||||
// FIXME convert to the type expected by the `dropck_outlives`
|
||||
// query. This should eventually be fixed by changing the
|
||||
// *underlying query*.
|
||||
let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| {
|
||||
let DropckOutlives { dropped_ty } = value;
|
||||
param_env.and(dropped_ty)
|
||||
});
|
||||
|
||||
tcx.dropck_outlives(canonicalized)
|
||||
}
|
||||
|
||||
|
|
@ -48,6 +29,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
|
|||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
compute_dropck_outlives_inner(ocx, key.param_env.and(key.value.dropped_ty))
|
||||
compute_dropck_outlives_inner(ocx, key.param_env.and(key.value))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_middle::traits::query::NoSolution;
|
|||
pub use rustc_middle::traits::query::type_op::ProvePredicate;
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
|
||||
|
||||
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
|
||||
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
||||
impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
|
||||
|
|
@ -49,7 +49,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
|
|||
|
||||
fn perform_query(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
|
||||
tcx.type_op_prove_predicate(canonicalized)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1018,7 +1018,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// #2 (region bounds).
|
||||
let principal_def_id_a = a_data.principal_def_id();
|
||||
let principal_def_id_b = b_data.principal_def_id();
|
||||
if principal_def_id_a == principal_def_id_b {
|
||||
if principal_def_id_a == principal_def_id_b || principal_def_id_b.is_none() {
|
||||
// We may upcast to auto traits that are either explicitly listed in
|
||||
// the object type's bounds, or implied by the principal trait ref's
|
||||
// supertraits.
|
||||
|
|
|
|||
|
|
@ -1153,6 +1153,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
|
||||
let iter = data_a
|
||||
.principal()
|
||||
.filter(|_| {
|
||||
// optionally drop the principal, if we're unsizing to no principal
|
||||
data_b.principal().is_some()
|
||||
})
|
||||
.map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
|
||||
.into_iter()
|
||||
.chain(
|
||||
|
|
|
|||
|
|
@ -154,18 +154,17 @@ fn prepare_vtable_segments_inner<'tcx, T>(
|
|||
|
||||
// emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
|
||||
while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() {
|
||||
let has_entries =
|
||||
has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id());
|
||||
|
||||
segment_visitor(VtblSegment::TraitOwnEntries {
|
||||
trait_ref: inner_most_trait_ref,
|
||||
emit_vptr: emit_vptr && !tcx.sess.opts.unstable_opts.no_trait_vptr,
|
||||
emit_vptr: emit_vptr && has_entries && !tcx.sess.opts.unstable_opts.no_trait_vptr,
|
||||
})?;
|
||||
|
||||
// If we've emitted (fed to `segment_visitor`) a trait that has methods present in the vtable,
|
||||
// we'll need to emit vptrs from now on.
|
||||
if !emit_vptr_on_new_entry
|
||||
&& has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id())
|
||||
{
|
||||
emit_vptr_on_new_entry = true;
|
||||
}
|
||||
emit_vptr_on_new_entry |= has_entries;
|
||||
|
||||
if let Some(next_inner_most_trait_ref) =
|
||||
siblings.find(|&sibling| visited.insert(sibling.upcast(tcx)))
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
|||
use rustc_trait_selection::traits::query::dropck_outlives::{
|
||||
compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner,
|
||||
};
|
||||
use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution};
|
||||
use rustc_trait_selection::traits::query::{CanonicalDropckOutlivesGoal, NoSolution};
|
||||
use tracing::debug;
|
||||
|
||||
pub(crate) fn provide(p: &mut Providers) {
|
||||
|
|
@ -19,7 +19,7 @@ pub(crate) fn provide(p: &mut Providers) {
|
|||
|
||||
fn dropck_outlives<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonical_goal: CanonicalTyGoal<'tcx>,
|
||||
canonical_goal: CanonicalDropckOutlivesGoal<'tcx>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, NoSolution> {
|
||||
debug!("dropck_outlives(goal={:#?})", canonical_goal);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,14 @@
|
|||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::infer::canonical::{self, Canonical};
|
||||
use rustc_infer::traits::query::OutlivesBound;
|
||||
use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::{
|
||||
compute_implied_outlives_bounds_compat_inner, compute_implied_outlives_bounds_inner,
|
||||
};
|
||||
use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution};
|
||||
use rustc_trait_selection::traits::query::{CanonicalImpliedOutlivesBoundsGoal, NoSolution};
|
||||
|
||||
pub(crate) fn provide(p: &mut Providers) {
|
||||
*p = Providers { implied_outlives_bounds_compat, ..*p };
|
||||
|
|
@ -20,26 +21,26 @@ pub(crate) fn provide(p: &mut Providers) {
|
|||
|
||||
fn implied_outlives_bounds_compat<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalTyGoal<'tcx>,
|
||||
goal: CanonicalImpliedOutlivesBoundsGoal<'tcx>,
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
|
||||
let (param_env, ty) = key.into_parts();
|
||||
let (param_env, ImpliedOutlivesBounds { ty }) = key.into_parts();
|
||||
compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty)
|
||||
})
|
||||
}
|
||||
|
||||
fn implied_outlives_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalTyGoal<'tcx>,
|
||||
goal: CanonicalImpliedOutlivesBoundsGoal<'tcx>,
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
|
||||
let (param_env, ty) = key.into_parts();
|
||||
let (param_env, ImpliedOutlivesBounds { ty }) = key.into_parts();
|
||||
compute_implied_outlives_bounds_inner(ocx, param_env, ty)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
||||
use rustc_infer::infer::canonical::{Canonical, CanonicalQueryInput, QueryResponse};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::{Clause, FnSig, ParamEnvAnd, PolyFnSig, Ty, TyCtxt, TypeFoldable};
|
||||
|
|
@ -28,7 +28,7 @@ pub(crate) fn provide(p: &mut Providers) {
|
|||
|
||||
fn type_op_ascribe_user_type<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
|
||||
type_op_ascribe_user_type_with_span(ocx, key, None)
|
||||
|
|
@ -51,35 +51,35 @@ where
|
|||
|
||||
fn type_op_normalize_ty<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Ty<'tcx>>>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<Ty<'tcx>>>>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, NoSolution> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize)
|
||||
}
|
||||
|
||||
fn type_op_normalize_clause<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Clause<'tcx>>>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<Clause<'tcx>>>>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Clause<'tcx>>>, NoSolution> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize)
|
||||
}
|
||||
|
||||
fn type_op_normalize_fn_sig<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<FnSig<'tcx>>>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<FnSig<'tcx>>>>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, FnSig<'tcx>>>, NoSolution> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize)
|
||||
}
|
||||
|
||||
fn type_op_normalize_poly_fn_sig<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<PolyFnSig<'tcx>>>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<PolyFnSig<'tcx>>>>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, PolyFnSig<'tcx>>>, NoSolution> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize)
|
||||
}
|
||||
|
||||
fn type_op_prove_predicate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>,
|
||||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
|
||||
type_op_prove_predicate_with_cause(ocx, key, ObligationCause::dummy());
|
||||
|
|
|
|||
|
|
@ -728,6 +728,49 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
|||
};
|
||||
}
|
||||
|
||||
if arg_idx.is_none() && arg.layout.size > Pointer(AddressSpace::DATA).size(cx) * 2 {
|
||||
// Return values larger than 2 registers using a return area
|
||||
// pointer. LLVM and Cranelift disagree about how to return
|
||||
// values that don't fit in the registers designated for return
|
||||
// values. LLVM will force the entire return value to be passed
|
||||
// by return area pointer, while Cranelift will look at each IR level
|
||||
// return value independently and decide to pass it in a
|
||||
// register or not, which would result in the return value
|
||||
// being passed partially in registers and partially through a
|
||||
// return area pointer.
|
||||
//
|
||||
// While Cranelift may need to be fixed as the LLVM behavior is
|
||||
// generally more correct with respect to the surface language,
|
||||
// forcing this behavior in rustc itself makes it easier for
|
||||
// other backends to conform to the Rust ABI and for the C ABI
|
||||
// rustc already handles this behavior anyway.
|
||||
//
|
||||
// In addition LLVM's decision to pass the return value in
|
||||
// registers or using a return area pointer depends on how
|
||||
// exactly the return type is lowered to an LLVM IR type. For
|
||||
// example `Option<u128>` can be lowered as `{ i128, i128 }`
|
||||
// in which case the x86_64 backend would use a return area
|
||||
// pointer, or it could be passed as `{ i32, i128 }` in which
|
||||
// case the x86_64 backend would pass it in registers by taking
|
||||
// advantage of an LLVM ABI extension that allows using 3
|
||||
// registers for the x86_64 sysv call conv rather than the
|
||||
// officially specified 2 registers.
|
||||
//
|
||||
// FIXME: Technically we should look at the amount of available
|
||||
// return registers rather than guessing that there are 2
|
||||
// registers for return values. In practice only a couple of
|
||||
// architectures have less than 2 return registers. None of
|
||||
// which supported by Cranelift.
|
||||
//
|
||||
// NOTE: This adjustment is only necessary for the Rust ABI as
|
||||
// for other ABI's the calling convention implementations in
|
||||
// rustc_target already ensure any return value which doesn't
|
||||
// fit in the available amount of return registers is passed in
|
||||
// the right way for the current target.
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
|
||||
match arg.layout.abi {
|
||||
Abi::Aggregate { .. } => {}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ use {rustc_abi as abi, rustc_hir as hir};
|
|||
use crate::errors::{
|
||||
MultipleArrayFieldsSimdType, NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType,
|
||||
};
|
||||
use crate::layout_sanity_check::sanity_check_layout;
|
||||
|
||||
mod invariant;
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { layout_of, ..*providers };
|
||||
|
|
@ -79,7 +80,7 @@ fn layout_of<'tcx>(
|
|||
record_layout_for_printing(&cx, layout);
|
||||
}
|
||||
|
||||
sanity_check_layout(&cx, &layout);
|
||||
invariant::partially_check_layout(&cx, &layout);
|
||||
|
||||
Ok(layout)
|
||||
}
|
||||
|
|
@ -115,6 +116,11 @@ fn map_error<'tcx>(
|
|||
cx.tcx().dcx().delayed_bug(format!("computed layout of empty union: {ty:?}"));
|
||||
LayoutError::Unknown(ty)
|
||||
}
|
||||
LayoutCalculatorError::ReprConflict => {
|
||||
// packed enums are the only known trigger of this, but others might arise
|
||||
cx.tcx().dcx().delayed_bug(format!("computed impossible repr (packed enum?): {ty:?}"));
|
||||
LayoutError::Unknown(ty)
|
||||
}
|
||||
};
|
||||
error(cx, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout};
|
|||
use rustc_target::abi::*;
|
||||
|
||||
/// Enforce some basic invariants on layouts.
|
||||
pub(super) fn sanity_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
|
||||
pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
|
||||
let tcx = cx.tcx();
|
||||
|
||||
// Type-level uninhabitedness should always imply ABI uninhabitedness.
|
||||
|
|
@ -29,7 +29,6 @@ mod errors;
|
|||
mod implied_bounds;
|
||||
mod instance;
|
||||
mod layout;
|
||||
mod layout_sanity_check;
|
||||
mod needs_drop;
|
||||
mod opaque_types;
|
||||
mod representability;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,18 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
|
|||
use crate::inherent::*;
|
||||
use crate::{self as ty, Interner, UniverseIndex};
|
||||
|
||||
#[derive_where(Clone; I: Interner, V: Clone)]
|
||||
#[derive_where(Hash; I: Interner, V: Hash)]
|
||||
#[derive_where(PartialEq; I: Interner, V: PartialEq)]
|
||||
#[derive_where(Eq; I: Interner, V: Eq)]
|
||||
#[derive_where(Debug; I: Interner, V: fmt::Debug)]
|
||||
#[derive_where(Copy; I: Interner, V: Copy)]
|
||||
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
|
||||
pub struct CanonicalQueryInput<I: Interner, V> {
|
||||
pub canonical: Canonical<I, V>,
|
||||
pub defining_opaque_types: I::DefiningOpaqueTypes,
|
||||
}
|
||||
|
||||
/// A "canonicalized" type `V` is one where all free inference
|
||||
/// variables have been rewritten to "canonical vars". These are
|
||||
/// numbered starting from 0 in order of first appearance.
|
||||
|
|
@ -24,8 +36,6 @@ use crate::{self as ty, Interner, UniverseIndex};
|
|||
pub struct Canonical<I: Interner, V> {
|
||||
pub value: V,
|
||||
pub max_universe: UniverseIndex,
|
||||
// FIXME(lcnr, oli-obk): try moving this into the query inputs instead
|
||||
pub defining_opaque_types: I::DefiningOpaqueTypes,
|
||||
pub variables: I::CanonicalVars,
|
||||
}
|
||||
|
||||
|
|
@ -54,27 +64,17 @@ impl<I: Interner, V> Canonical<I, V> {
|
|||
/// let b: Canonical<I, (T, Ty<I>)> = a.unchecked_map(|v| (v, ty));
|
||||
/// ```
|
||||
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> {
|
||||
let Canonical { defining_opaque_types, max_universe, variables, value } = self;
|
||||
Canonical { defining_opaque_types, max_universe, variables, value: map_op(value) }
|
||||
}
|
||||
|
||||
/// Allows you to map the `value` of a canonical while keeping the same set of
|
||||
/// bound variables.
|
||||
///
|
||||
/// **WARNING:** This function is very easy to mis-use, hence the name! See
|
||||
/// the comment of [Canonical::unchecked_map] for more details.
|
||||
pub fn unchecked_rebind<W>(self, value: W) -> Canonical<I, W> {
|
||||
let Canonical { defining_opaque_types, max_universe, variables, value: _ } = self;
|
||||
Canonical { defining_opaque_types, max_universe, variables, value }
|
||||
let Canonical { max_universe, variables, value } = self;
|
||||
Canonical { max_universe, variables, value: map_op(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { value, max_universe, variables, defining_opaque_types } = self;
|
||||
let Self { value, max_universe, variables } = self;
|
||||
write!(
|
||||
f,
|
||||
"Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?}, defining_opaque_types: {defining_opaque_types:?} }}",
|
||||
"Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?} }}",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -714,7 +714,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
|||
// current goal is already part of the same cycle. This check could be
|
||||
// improved but seems to be good enough for now.
|
||||
let last = self.stack.raw.last().unwrap();
|
||||
if !last.heads.opt_lowest_cycle_head().is_some_and(|lowest| lowest <= head) {
|
||||
if last.heads.opt_lowest_cycle_head().is_none_or(|lowest| lowest > head) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue