Auto merge of #18364 - lnicola:sync-from-rust, r=lnicola

minor: sync from downstream
This commit is contained in:
bors 2024-10-22 07:21:22 +00:00
commit ca51c1e72c
741 changed files with 11363 additions and 7386 deletions

View File

@ -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
View File

@ -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

View File

@ -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>

View File

@ -377,7 +377,7 @@ dependencies = [
"cargo_metadata",
"directories",
"rustc-build-sysroot",
"rustc_tools_util 0.4.0",
"rustc_tools_util",
"rustc_version",
"serde",
"serde_json",
@ -537,7 +537,7 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "clippy"
version = "0.1.83"
version = "0.1.84"
dependencies = [
"anstream",
"cargo_metadata",
@ -550,9 +550,11 @@ dependencies = [
"if_chain",
"itertools",
"parking_lot",
"pulldown-cmark 0.11.3",
"quote",
"regex",
"rustc_tools_util 0.3.0",
"rinja",
"rustc_tools_util",
"serde",
"serde_json",
"syn 2.0.79",
@ -566,7 +568,7 @@ dependencies = [
[[package]]
name = "clippy_config"
version = "0.1.83"
version = "0.1.84"
dependencies = [
"itertools",
"serde",
@ -582,20 +584,19 @@ dependencies = [
"clap",
"indoc",
"itertools",
"opener 0.6.1",
"opener",
"shell-escape",
"walkdir",
]
[[package]]
name = "clippy_lints"
version = "0.1.83"
version = "0.1.84"
dependencies = [
"arrayvec",
"cargo_metadata",
"clippy_config",
"clippy_utils",
"declare_clippy_lint",
"itertools",
"quine-mc_cluskey",
"regex",
@ -613,7 +614,7 @@ dependencies = [
[[package]]
name = "clippy_utils"
version = "0.1.83"
version = "0.1.84"
dependencies = [
"arrayvec",
"clippy_config",
@ -919,15 +920,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "declare_clippy_lint"
version = "0.1.83"
dependencies = [
"itertools",
"quote",
"syn 2.0.79",
]
[[package]]
name = "deranged"
version = "0.3.11"
@ -1915,7 +1907,7 @@ dependencies = [
"anyhow",
"clap",
"fs-err",
"rustc-hash 1.1.0",
"rustc-hash 2.0.0",
"rustdoc-json-types",
"serde",
"serde_json",
@ -2163,7 +2155,7 @@ dependencies = [
"log",
"memchr",
"once_cell",
"opener 0.7.2",
"opener",
"pulldown-cmark 0.10.3",
"regex",
"serde",
@ -2501,17 +2493,6 @@ dependencies = [
"stable_deref_trait",
]
[[package]]
name = "opener"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c62dcb6174f9cb326eac248f07e955d5d559c272730b6c03e396b443b562788"
dependencies = [
"bstr",
"normpath",
"winapi",
]
[[package]]
name = "opener"
version = "0.7.2"
@ -2879,6 +2860,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625"
dependencies = [
"bitflags 2.6.0",
"getopts",
"memchr",
"pulldown-cmark-escape 0.11.0",
"unicase",
@ -3532,7 +3514,7 @@ dependencies = [
"memmap2",
"parking_lot",
"portable-atomic",
"rustc-hash 1.1.0",
"rustc-hash 2.0.0",
"rustc-rayon",
"rustc-stable-hash",
"rustc_arena",
@ -4229,7 +4211,7 @@ dependencies = [
name = "rustc_pattern_analysis"
version = "0.0.0"
dependencies = [
"rustc-hash 1.1.0",
"rustc-hash 2.0.0",
"rustc_apfloat",
"rustc_arena",
"rustc_data_structures",
@ -4460,12 +4442,6 @@ dependencies = [
"tracing",
]
[[package]]
name = "rustc_tools_util"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
[[package]]
name = "rustc_tools_util"
version = "0.4.0"
@ -4608,6 +4584,7 @@ dependencies = [
"rustdoc-json-types",
"serde",
"serde_json",
"sha2",
"smallvec",
"tempfile",
"threadpool",
@ -4632,7 +4609,7 @@ name = "rustdoc-json-types"
version = "0.1.0"
dependencies = [
"bincode",
"rustc-hash 1.1.0",
"rustc-hash 2.0.0",
"serde",
"serde_json",
]
@ -5262,7 +5239,7 @@ dependencies = [
"ignore",
"miropt-test-tools",
"regex",
"rustc-hash 1.1.0",
"rustc-hash 2.0.0",
"semver",
"similar",
"termcolor",
@ -5593,13 +5570,6 @@ dependencies = [
"version_check",
]
[[package]]
name = "unicode-bdd"
version = "0.1.0"
dependencies = [
"ucd-parse",
]
[[package]]
name = "unicode-bidi"
version = "0.3.15"
@ -5649,6 +5619,13 @@ version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-table-generator"
version = "0.1.0"
dependencies = [
"ucd-parse",
]
[[package]]
name = "unicode-width"
version = "0.1.14"

View File

@ -3,18 +3,23 @@ mod abi {
pub(crate) use crate::Variants;
}
#[cfg(feature = "nightly")]
use rustc_macros::HashStable_Generic;
use crate::{Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
#[cfg(feature = "nightly")]
use crate::{Abi, FieldsShape, TyAbiInterface, TyAndLayout};
use crate::{Align, HasDataLayout, Size};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum RegKind {
Integer,
Float,
Vector,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Reg {
pub kind: RegKind,
pub size: Size,
@ -108,15 +113,8 @@ impl HomogeneousAggregate {
}
}
#[cfg(feature = "nightly")]
impl<'a, Ty> TyAndLayout<'a, Ty> {
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
pub fn is_aggregate(&self) -> bool {
match self.abi {
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
}
}
/// Returns `Homogeneous` if this layout is an aggregate containing fields of
/// only a single type (e.g., `(u32, u32)`). Such aggregates are often
/// special-cased in ABIs.

View File

@ -11,8 +11,10 @@ use crate::{
Variants, WrappingRange,
};
#[cfg(feature = "nightly")]
mod ty;
#[cfg(feature = "nightly")]
pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
// A variant is absent if it's uninhabited and only has ZST fields.
@ -39,7 +41,7 @@ enum NicheBias {
End,
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum LayoutCalculatorError<F> {
/// An unsized type was found in a location where a sized type was expected.
///
@ -54,6 +56,36 @@ pub enum LayoutCalculatorError<F> {
/// A union had no fields.
EmptyUnion,
/// The fields or variants have irreconcilable reprs
ReprConflict,
}
impl<F> LayoutCalculatorError<F> {
pub fn without_payload(&self) -> LayoutCalculatorError<()> {
match self {
LayoutCalculatorError::UnexpectedUnsized(_) => {
LayoutCalculatorError::UnexpectedUnsized(())
}
LayoutCalculatorError::SizeOverflow => LayoutCalculatorError::SizeOverflow,
LayoutCalculatorError::EmptyUnion => LayoutCalculatorError::EmptyUnion,
LayoutCalculatorError::ReprConflict => LayoutCalculatorError::ReprConflict,
}
}
/// Format an untranslated diagnostic for this type
///
/// Intended for use by rust-analyzer, as neither it nor `rustc_abi` depend on fluent infra.
pub fn fallback_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
LayoutCalculatorError::UnexpectedUnsized(_) => {
"an unsized type was found where a sized type was expected"
}
LayoutCalculatorError::SizeOverflow => "size overflow",
LayoutCalculatorError::EmptyUnion => "type is a union with no fields",
LayoutCalculatorError::ReprConflict => "type has an invalid repr",
})
}
}
type LayoutCalculatorResult<FieldIdx, VariantIdx, F> =
@ -489,6 +521,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}
let dl = self.cx.data_layout();
// bail if the enum has an incoherent repr that cannot be computed
if repr.packed() {
return Err(LayoutCalculatorError::ReprConflict);
}
let calculate_niche_filling_layout = || -> Option<TmpLayout<FieldIdx, VariantIdx>> {
if dont_niche_optimize_enum {

View File

@ -29,14 +29,14 @@ mod layout;
mod tests;
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
pub use layout::{
FIRST_VARIANT, FieldIdx, Layout, LayoutCalculator, LayoutCalculatorError, TyAbiInterface,
TyAndLayout, VariantIdx,
};
#[cfg(feature = "nightly")]
pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
pub use layout::{LayoutCalculator, LayoutCalculatorError};
/// Requirements for a `StableHashingContext` to be used in this crate.
/// This is a hack to allow using the `HashStable_Generic` derive macro
/// instead of implementing everything in `rustc_middle`.
#[cfg(feature = "nightly")]
pub trait HashStableContext {}
#[derive(Clone, Copy, PartialEq, Eq, Default)]
@ -1644,6 +1644,14 @@ pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> {
}
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
pub fn is_aggregate(&self) -> bool {
match self.abi {
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
}
}
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
let size = scalar.size(cx);

View File

@ -23,7 +23,6 @@
#![feature(maybe_uninit_slice)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![feature(strict_provenance)]
#![warn(unreachable_pub)]
// tidy-alphabetical-end

View File

@ -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,

View File

@ -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();

View File

@ -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
}

View File

@ -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,
}

View File

@ -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();

View File

@ -187,10 +187,10 @@ fn do_mir_borrowck<'tcx>(
let location_table = LocationTable::new(body);
let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
let move_data = MoveData::gather_moves(body, tcx, |_| true);
let promoted_move_data = promoted
.iter_enumerated()
.map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, param_env, |_| true)));
.map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true)));
let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
.into_engine(tcx, body)

View File

@ -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 }),
);
}

View File

@ -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()?;

View File

@ -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, .. }) => {

View File

@ -1128,7 +1128,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
let projected_ty = curr_projected_ty.projection_ty_core(
tcx,
self.param_env,
proj,
|this, field, ()| {
let ty = this.field_ty(tcx, field);
@ -1919,7 +1918,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// than 1.
// If the length is larger than 1, the repeat expression will need to copy the
// element, so we require the `Copy` trait.
if len.try_eval_target_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
if len.try_to_target_usize(tcx).is_none_or(|len| len > 1) {
match operand {
Operand::Copy(..) | Operand::Constant(..) => {
// These are always okay: direct use of a const, or a value that can evidently be copied.

View File

@ -133,6 +133,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
.expect_const()
.try_to_valtree()
.expect("expected monomorphic const in codegen")
.0
.unwrap_branch();
assert_eq!(x.layout(), y.layout());
@ -806,8 +807,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => m.load_scalar(fx),
ty::Array(elem, len)
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
&& len.try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all())
== Some(expected_bytes) =>
&& len
.try_to_target_usize(fx.tcx)
.expect("expected monomorphic const in codegen")
== expected_bytes =>
{
m.force_stack(fx).0.load(
fx,
@ -907,8 +910,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {}
ty::Array(elem, len)
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
&& len.try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all())
== Some(expected_bytes) => {}
&& len
.try_to_target_usize(fx.tcx)
.expect("expected monomorphic const in codegen")
== expected_bytes => {}
_ => {
fx.tcx.dcx().span_fatal(
span,

View File

@ -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}"

View File

@ -76,8 +76,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
ty::Array(elem, len)
if matches!(*elem.kind(), ty::Uint(ty::UintTy::U8))
&& len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
== Some(expected_bytes) =>
&& len
.try_to_target_usize(bx.tcx)
.expect("expected monomorphic const in codegen")
== expected_bytes =>
{
let place = PlaceRef::alloca(bx, args[0].layout);
args[0].val.store(bx, place);
@ -696,8 +698,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
}
ty::Array(elem, len)
if matches!(*elem.kind(), ty::Uint(ty::UintTy::U8))
&& len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
== Some(expected_bytes) =>
&& len
.try_to_target_usize(bx.tcx)
.expect("expected monomorphic const in codegen")
== expected_bytes =>
{
// Zero-extend iN to the array length:
let ze = bx.zext(result, bx.type_ix(expected_bytes * 8));

View File

@ -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,

View File

@ -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")
}

View File

@ -787,7 +787,9 @@ fn codegen_msvc_try<'ll>(
let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
unsafe {
llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
llvm::SetUniqueComdat(bx.llmod, tydesc);
if bx.cx.tcx.sess.target.supports_comdat() {
llvm::SetUniqueComdat(bx.llmod, tydesc);
}
llvm::LLVMSetInitializer(tydesc, type_info);
}
@ -1177,8 +1179,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
ty::Array(elem, len)
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
&& len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
== Some(expected_bytes) =>
&& len
.try_to_target_usize(bx.tcx)
.expect("expected monomorphic const in codegen")
== expected_bytes =>
{
let place = PlaceRef::alloca(bx, args[0].layout);
args[0].val.store(bx, place);
@ -1243,12 +1247,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
if name == sym::simd_shuffle_generic {
let idx = fn_args[2]
.expect_const()
.eval(tcx, ty::ParamEnv::reveal_all(), span)
.unwrap()
.1
.unwrap_branch();
let idx = fn_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch();
let n = idx.len() as u64;
let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn);
@ -1467,8 +1466,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
ty::Array(elem, len)
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
&& len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
== Some(expected_bytes) =>
&& len
.try_to_target_usize(bx.tcx)
.expect("expected monomorphic const in codegen")
== expected_bytes =>
{
// Zero-extend iN to the array length:
let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8));

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -23,7 +23,6 @@ use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
use rustc_middle::ty::{
self, ExistentialProjection, GenericArgKind, GenericArgsRef, ParamEnv, Ty, TyCtxt,
};
use rustc_span::DUMMY_SP;
use rustc_target::abi::Integer;
use smallvec::SmallVec;
@ -685,21 +684,25 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
ty::ConstKind::Param(param) => {
write!(output, "{}", param.name)
}
ty::ConstKind::Value(ty, _) => {
ty::ConstKind::Value(ty, valtree) => {
match ty.kind() {
ty::Int(ity) => {
// FIXME: directly extract the bits from a valtree instead of evaluating an
// already evaluated `Const` in order to get the bits.
let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
let bits = ct
.try_to_bits(tcx, ty::ParamEnv::reveal_all())
.expect("expected monomorphic const in codegen");
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
write!(output, "{val}")
}
ty::Uint(_) => {
let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
let val = ct
.try_to_bits(tcx, ty::ParamEnv::reveal_all())
.expect("expected monomorphic const in codegen");
write!(output, "{val}")
}
ty::Bool => {
let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap();
let val = ct.try_to_bool().expect("expected monomorphic const in codegen");
write!(output, "{val}")
}
_ => {
@ -711,8 +714,9 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
// avoiding collisions and will make the emitted type names shorter.
let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
let mut hasher = StableHasher::new();
let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP).unwrap();
hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher));
hcx.while_hashing_spans(false, |hcx| {
(ty, valtree).hash_stable(hcx, &mut hasher)
});
hasher.finish::<Hash64>()
});

View File

@ -11,7 +11,6 @@
#![feature(let_chains)]
#![feature(negative_impls)]
#![feature(rustdoc_internals)]
#![feature(strict_provenance)]
#![feature(trait_alias)]
#![feature(try_blocks)]
#![warn(unreachable_pub)]

View File

@ -361,12 +361,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
(Pointer(..), Int(..)) => bx.ptrtoint(imm, to_backend_ty),
(Pointer(..), Int(..)) => {
// FIXME: this exposes the provenance, which shouldn't be necessary.
bx.ptrtoint(imm, to_backend_ty)
}
(Float(_), Pointer(..)) => {
let int_imm = bx.bitcast(imm, bx.cx().type_isize());
bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
}
(Pointer(..), Float(_)) => {
// FIXME: this exposes the provenance, which shouldn't be necessary.
let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
bx.bitcast(int_imm, to_backend_ty)
}

View File

@ -6,13 +6,10 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*;
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
use rustc_middle::{bug, mir};
use rustc_trait_selection::traits::{
ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
};
use tracing::{instrument, trace};
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
use tracing::instrument;
use super::ConstCx;
@ -195,50 +192,8 @@ impl Qualif for NeedsNonConstDrop {
return false;
}
// FIXME(effects): If `destruct` is not a `const_trait`,
// or effects are disabled in this crate, then give up.
let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span));
if !cx.tcx.has_host_param(destruct_def_id) || !cx.tcx.features().effects {
return NeedsDrop::in_any_value_of_ty(cx, ty);
}
let obligation = Obligation::new(
cx.tcx,
ObligationCause::dummy_with_span(cx.body.span),
cx.param_env,
ty::TraitRef::new(cx.tcx, destruct_def_id, [
ty::GenericArg::from(ty),
ty::GenericArg::from(cx.tcx.expected_host_effect_param_for_body(cx.def_id())),
]),
);
let infcx = cx.tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
// If we couldn't select a const destruct candidate, then it's bad
return true;
};
trace!(?impl_src);
if !matches!(
impl_src,
ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(_)
) {
// If our const destruct candidate is not ConstDestruct or implied by the param env,
// then it's bad
return true;
}
if impl_src.borrow_nested_obligations().is_empty() {
return false;
}
// If we had any errors, then it's bad
let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligations(impl_src.nested_obligations());
let errors = ocx.select_all_or_error();
!errors.is_empty()
// FIXME(effects): Reimplement const drop checking.
NeedsDrop::in_any_value_of_ty(cx, ty)
}
fn in_adt_inherently<'tcx>(

View File

@ -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,

View File

@ -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);
}

View File

@ -43,7 +43,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
// We go to `usize` as we cannot allocate anything bigger anyway.
let (field_count, variant, down) = match ty.kind() {
ty::Array(_, len) => (len.eval_target_usize(tcx.tcx, param_env) as usize, None, op),
ty::Array(_, len) => (len.try_to_target_usize(tcx.tcx)? as usize, None, op),
ty::Adt(def, _) if def.variants().is_empty() => {
return None;
}

View File

@ -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);
}),
}

View File

@ -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();
})

View File

@ -391,7 +391,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let ptr = self.read_pointer(src)?;
let val = Immediate::new_slice(
ptr,
length.eval_target_usize(*self.tcx, self.param_env),
length
.try_to_target_usize(*self.tcx)
.expect("expected monomorphic const in const eval"),
self,
);
self.write_immediate(val, dest)

View File

@ -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) => {

View File

@ -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.

View File

@ -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: {}",

View File

@ -10,7 +10,6 @@
#![feature(never_type)]
#![feature(rustdoc_internals)]
#![feature(slice_ptr_get)]
#![feature(strict_provenance)]
#![feature(trait_alias)]
#![feature(try_blocks)]
#![feature(unqualified_local_imports)]

View File

@ -13,7 +13,7 @@ ena = "0.14.3"
indexmap = { version = "2.4.0" }
jobserver_crate = { version = "0.1.28", package = "jobserver" }
measureme = "11"
rustc-hash = "1.1.0"
rustc-hash = "2.0.0"
rustc-rayon = { version = "0.5.0", optional = true }
rustc-stable-hash = { version = "0.1.0", features = ["nightly"] }
rustc_arena = { path = "../rustc_arena" }

View File

@ -33,7 +33,6 @@
#![feature(ptr_alignment_type)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![feature(strict_provenance)]
#![feature(test)]
#![feature(thread_id_value)]
#![feature(type_alias_impl_trait)]

View File

@ -353,6 +353,9 @@ declare_features! (
(accepted, repr_packed, "1.33.0", Some(33158)),
/// Allows `#[repr(transparent)]` attribute on newtype structs.
(accepted, repr_transparent, "1.28.0", Some(43036)),
/// Allows enums like Result<T, E> to be used across FFI, if T's niche value can
/// be used to describe E or vice-versa.
(accepted, result_ffi_guarantees, "CURRENT_RUSTC_VERSION", Some(110503)),
/// Allows return-position `impl Trait` in traits.
(accepted, return_position_impl_trait_in_trait, "1.75.0", Some(91611)),
/// Allows code like `let x: &'static u32 = &42` to work (RFC 1414).

View File

@ -580,9 +580,6 @@ declare_features! (
(incomplete, repr128, "1.16.0", Some(56071)),
/// Allows `repr(simd)` and importing the various simd intrinsics.
(unstable, repr_simd, "1.4.0", Some(27731)),
/// Allows enums like Result<T, E> to be used across FFI, if T's niche value can
/// be used to describe E or vise-versa.
(unstable, result_ffi_guarantees, "1.80.0", Some(110503)),
/// Allows bounding the return type of AFIT/RPITIT.
(unstable, return_type_notation, "1.70.0", Some(109417)),
/// Allows `extern "rust-cold"`.
@ -598,7 +595,7 @@ declare_features! (
/// Allows attributes on expressions and non-item statements.
(unstable, stmt_expr_attributes, "1.6.0", Some(15701)),
/// Allows lints part of the strict provenance effort.
(unstable, strict_provenance, "1.61.0", Some(95228)),
(unstable, strict_provenance_lints, "1.61.0", Some(130351)),
/// Allows string patterns to dereference values to match them.
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
/// Allows the use of `#[target_feature]` on safe functions.

View File

@ -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) => {

View File

@ -6,6 +6,7 @@
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_span)]
#![feature(rustdoc_internals)]
#![feature(track_path)]
#![warn(unreachable_pub)]
// tidy-alphabetical-end

View File

@ -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

View File

@ -9,7 +9,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use crate::hir_ty_lowering::OnlySelfBounds;
use crate::hir_ty_lowering::PredicateFilter;
/// Collects together a list of type bounds. These lists of bounds occur in many places
/// in Rust's syntax:
@ -51,8 +51,8 @@ impl<'tcx> Bounds<'tcx> {
bound_trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
polarity: ty::PredicatePolarity,
constness: ty::BoundConstness,
only_self_bounds: OnlySelfBounds,
constness: Option<ty::BoundConstness>,
predicate_filter: PredicateFilter,
) {
let clause = (
bound_trait_ref
@ -72,26 +72,36 @@ impl<'tcx> Bounds<'tcx> {
// FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else.
// Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated
// type bounds.
if !tcx.features().effects || only_self_bounds.0 {
if !tcx.features().effects {
return;
}
match predicate_filter {
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
return;
}
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
// Ok.
}
}
// For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the
// associated type of `<T as Tr>` and make sure that the effect is compatible.
let compat_val = match (tcx.def_kind(defining_def_id), constness) {
// FIXME(effects): revisit the correctness of this
(_, ty::BoundConstness::Const) => tcx.consts.false_,
(_, Some(ty::BoundConstness::Const)) => tcx.consts.false_,
// body owners that can have trait bounds
(DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => {
tcx.expected_host_effect_param_for_body(defining_def_id)
}
(
DefKind::Const | DefKind::Fn | DefKind::AssocFn,
Some(ty::BoundConstness::ConstIfConst),
) => tcx.expected_host_effect_param_for_body(defining_def_id),
(_, ty::BoundConstness::NotConst) => {
(_, None) => {
if !tcx.is_const_trait(bound_trait_ref.def_id()) {
return;
}
tcx.consts.true_
}
(DefKind::Trait, ty::BoundConstness::ConstIfConst) => {
(DefKind::Trait, Some(ty::BoundConstness::ConstIfConst)) => {
// we are in a trait, where `bound_trait_ref` could be:
// (1) a super trait `trait Foo: ~const Bar`.
// - This generates `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>`
@ -129,7 +139,7 @@ impl<'tcx> Bounds<'tcx> {
return;
}
(DefKind::Impl { of_trait: true }, ty::BoundConstness::ConstIfConst) => {
(DefKind::Impl { of_trait: true }, Some(ty::BoundConstness::ConstIfConst)) => {
// this is a where clause on an impl header.
// push `<T as Tr>::Effects` into the set for the `Min` bound.
let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
@ -163,12 +173,12 @@ impl<'tcx> Bounds<'tcx> {
//
// FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor
// that uses a `Bar` that implements `Trait` with `Maybe` effects.
(DefKind::AssocTy, ty::BoundConstness::ConstIfConst) => {
(DefKind::AssocTy, Some(ty::BoundConstness::ConstIfConst)) => {
// FIXME(effects): implement this
return;
}
// probably illegal in this position.
(_, ty::BoundConstness::ConstIfConst) => {
(_, Some(ty::BoundConstness::ConstIfConst)) => {
tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered");
return;
}

View File

@ -22,7 +22,7 @@ use rustc_middle::ty::{
AdtDef, GenericArgKind, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt,
};
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_session::lint::builtin::UNINHABITED_STATIC;
use rustc_target::abi::FieldIdx;
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective;
@ -36,36 +36,25 @@ use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_i
use super::*;
use crate::check::intrinsicck::InlineAsmCtxt;
pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
match tcx.sess.target.is_abi_supported(abi) {
Some(true) => (),
Some(false) => {
struct_span_code_err!(
tcx.dcx(),
span,
E0570,
"`{abi}` is not a supported ABI for the current target",
)
.emit();
}
None => {
tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
lint.primary_message("use of calling convention not supported on this target");
});
}
pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) {
if !tcx.sess.target.is_abi_supported(abi) {
struct_span_code_err!(
tcx.dcx(),
span,
E0570,
"`{abi}` is not a supported ABI for the current target",
)
.emit();
}
}
pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
match tcx.sess.target.is_abi_supported(abi) {
Some(true) => (),
Some(false) | None => {
tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
lint.primary_message(format!(
"the calling convention {abi} is not supported on this target"
));
});
}
if !tcx.sess.target.is_abi_supported(abi) {
tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
lint.primary_message(format!(
"the calling convention {abi} is not supported on this target"
));
});
}
}
@ -705,7 +694,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let hir::ItemKind::ForeignMod { abi, items } = it.kind else {
return;
};
check_abi(tcx, it.hir_id(), it.span, abi);
check_abi(tcx, it.span, abi);
match abi {
Abi::RustIntrinsic => {
@ -1037,7 +1026,11 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
return;
}
if let Some(len) = len_const.try_eval_target_usize(tcx, tcx.param_env(def.did())) {
// FIXME(repr_simd): This check is nice, but perhaps unnecessary due to the fact
// we do not expect users to implement their own `repr(simd)` types. If they could,
// this check is easily side-steppable by hiding the const behind normalization.
// The consequence is that the error is, in general, only observable post-mono.
if let Some(len) = len_const.try_to_target_usize(tcx) {
if len == 0 {
struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
return;

View File

@ -76,9 +76,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
let (size, ty) = match elem_ty.kind() {
ty::Array(ty, len) => {
if let Some(len) =
len.try_eval_target_usize(self.tcx, self.tcx.param_env(adt.did()))
{
if let Some(len) = len.try_to_target_usize(self.tcx) {
(len, *ty)
} else {
return None;

View File

@ -13,6 +13,7 @@ use tracing::{debug, instrument};
use super::ItemCtxt;
use super::predicates_of::assert_only_contains_predicates_from;
use crate::bounds::Bounds;
use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter};
/// For associated types we include both bounds written on the type
@ -36,7 +37,8 @@ fn associated_type_bounds<'tcx>(
);
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter);
let mut bounds = Bounds::default();
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
// Associated types are implicitly sized unless a `?Sized` bound is found
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
@ -303,7 +305,8 @@ fn opaque_type_bounds<'tcx>(
) -> &'tcx [(ty::Clause<'tcx>, Span)] {
ty::print::with_reduced_queries!({
let icx = ItemCtxt::new(tcx, opaque_def_id);
let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter);
let mut bounds = Bounds::default();
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
// Opaque types are implicitly sized unless a `?Sized` bound is found
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
debug!(?bounds);

View File

@ -16,7 +16,7 @@ use crate::bounds::Bounds;
use crate::collect::ItemCtxt;
use crate::constrained_generic_params as cgp;
use crate::delegation::inherit_predicates_for_delegation_item;
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason};
use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason};
/// Returns a list of all type predicates (explicit and implicit) for the definition with
/// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus
@ -181,9 +181,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// on a trait we must also consider the bounds that follow the trait's name,
// like `trait Foo: A + B + C`.
if let Some(self_bounds) = is_trait {
let bounds = icx.lowerer().lower_mono_bounds(
let mut bounds = Bounds::default();
icx.lowerer().lower_bounds(
tcx.types.self_param,
self_bounds,
&mut bounds,
ty::List::empty(),
PredicateFilter::All,
);
predicates.extend(bounds.clauses(tcx));
@ -265,12 +268,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}
let mut bounds = Bounds::default();
icx.lowerer().lower_poly_bounds(
icx.lowerer().lower_bounds(
ty,
bound_pred.bounds.iter(),
bound_pred.bounds,
&mut bounds,
bound_vars,
OnlySelfBounds(false),
PredicateFilter::All,
);
predicates.extend(bounds.clauses(tcx));
effects_min_tys.extend(bounds.effects_min_tys());
@ -626,7 +629,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
bug!("trait_def_id {trait_def_id:?} is not an item");
};
let (generics, bounds) = match item.kind {
let (generics, superbounds) = match item.kind {
hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits),
hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits),
_ => span_bug!(item.span, "super_predicates invoked on non-trait"),
@ -635,7 +638,8 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
let icx = ItemCtxt::new(tcx, trait_def_id);
let self_param_ty = tcx.types.self_param;
let superbounds = icx.lowerer().lower_mono_bounds(self_param_ty, bounds, filter);
let mut bounds = Bounds::default();
icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter);
let where_bounds_that_match = icx.probe_ty_param_bounds_in_generics(
generics,
@ -646,7 +650,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
// Combine the two lists to form the complete set of superbounds:
let implied_bounds =
&*tcx.arena.alloc_from_iter(superbounds.clauses(tcx).chain(where_bounds_that_match));
&*tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(where_bounds_that_match));
debug!(?implied_bounds);
// Now require that immediate supertraits are lowered, which will, in
@ -825,20 +829,6 @@ impl<'tcx> ItemCtxt<'tcx> {
continue;
};
// Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we
// want to only consider predicates with `Self: ...`, but we don't want
// `OnlySelfBounds(true)` since we want to collect the nested associated
// type bound as well.
let (only_self_bounds, assoc_name) = match filter {
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
(OnlySelfBounds(false), None)
}
PredicateFilter::SelfOnly => (OnlySelfBounds(true), None),
PredicateFilter::SelfThatDefines(assoc_name) => {
(OnlySelfBounds(true), Some(assoc_name))
}
};
let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
ty
} else if matches!(filter, PredicateFilter::All) {
@ -848,33 +838,15 @@ impl<'tcx> ItemCtxt<'tcx> {
};
let bound_vars = self.tcx.late_bound_vars(predicate.hir_id);
self.lowerer().lower_poly_bounds(
self.lowerer().lower_bounds(
bound_ty,
predicate.bounds.iter().filter(|bound| {
assoc_name
.map_or(true, |assoc_name| self.bound_defines_assoc_item(bound, assoc_name))
}),
predicate.bounds,
&mut bounds,
bound_vars,
only_self_bounds,
filter,
);
}
bounds.clauses(self.tcx).collect()
}
#[instrument(level = "trace", skip(self))]
fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
match b {
hir::GenericBound::Trait(poly_trait_ref) => {
let trait_ref = &poly_trait_ref.trait_ref;
if let Some(trait_did) = trait_ref.trait_def_id() {
self.tcx.trait_may_define_assoc_item(trait_did, assoc_name)
} else {
false
}
}
_ => false,
}
}
}

View File

@ -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: (),
},

View File

@ -19,9 +19,7 @@ use tracing::{debug, instrument};
use super::errors::GenericsArgsErrExtend;
use crate::bounds::Bounds;
use crate::errors;
use crate::hir_ty_lowering::{
AssocItemQSelf, HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason,
};
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer, PredicateFilter, RegionInferReason};
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// Add a `Sized` bound to the `bounds` if appropriate.
@ -144,31 +142,44 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// There is an implied binder around `param_ty` and `hir_bounds`.
/// See `lower_poly_trait_ref` for more details.
#[instrument(level = "debug", skip(self, hir_bounds, bounds))]
pub(crate) fn lower_poly_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'tcx>>>(
pub(crate) fn lower_bounds<'hir, I: IntoIterator<Item = &'hir hir::GenericBound<'tcx>>>(
&self,
param_ty: Ty<'tcx>,
hir_bounds: I,
bounds: &mut Bounds<'tcx>,
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
only_self_bounds: OnlySelfBounds,
predicate_filter: PredicateFilter,
) where
'tcx: 'hir,
{
for hir_bound in hir_bounds {
// In order to avoid cycles, when we're lowering `SelfThatDefines`,
// we skip over any traits that don't define the given associated type.
if let PredicateFilter::SelfThatDefines(assoc_name) = predicate_filter {
if let Some(trait_ref) = hir_bound.trait_ref()
&& let Some(trait_did) = trait_ref.trait_def_id()
&& self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
{
// Okay
} else {
continue;
}
}
match hir_bound {
hir::GenericBound::Trait(poly_trait_ref) => {
let (constness, polarity) = match poly_trait_ref.modifiers {
hir::TraitBoundModifier::Const => {
(ty::BoundConstness::Const, ty::PredicatePolarity::Positive)
}
hir::TraitBoundModifier::MaybeConst => {
(ty::BoundConstness::ConstIfConst, ty::PredicatePolarity::Positive)
}
hir::TraitBoundModifier::None => {
(ty::BoundConstness::NotConst, ty::PredicatePolarity::Positive)
(Some(ty::BoundConstness::Const), ty::PredicatePolarity::Positive)
}
hir::TraitBoundModifier::MaybeConst => (
Some(ty::BoundConstness::ConstIfConst),
ty::PredicatePolarity::Positive,
),
hir::TraitBoundModifier::None => (None, ty::PredicatePolarity::Positive),
hir::TraitBoundModifier::Negative => {
(ty::BoundConstness::NotConst, ty::PredicatePolarity::Negative)
(None, ty::PredicatePolarity::Negative)
}
hir::TraitBoundModifier::Maybe => continue,
};
@ -179,7 +190,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
polarity,
param_ty,
bounds,
only_self_bounds,
predicate_filter,
);
}
hir::GenericBound::Outlives(lifetime) => {
@ -200,56 +211,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
/// Lower HIR bounds into `bounds` given the self type `param_ty` and *no* overarching late-bound vars.
///
/// ### Example
///
/// ```ignore (illustrative)
/// fn foo<T: Bar + Baz>() { }
/// // ^ ^^^^^^^^^ hir_bounds
/// // param_ty
/// ```
pub(crate) fn lower_mono_bounds(
&self,
param_ty: Ty<'tcx>,
hir_bounds: &[hir::GenericBound<'tcx>],
filter: PredicateFilter,
) -> Bounds<'tcx> {
let mut bounds = Bounds::default();
let only_self_bounds = match filter {
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
OnlySelfBounds(false)
}
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => OnlySelfBounds(true),
};
self.lower_poly_bounds(
param_ty,
hir_bounds.iter().filter(|bound| match filter {
PredicateFilter::All
| PredicateFilter::SelfOnly
| PredicateFilter::SelfAndAssociatedTypeBounds => true,
PredicateFilter::SelfThatDefines(assoc_name) => {
if let Some(trait_ref) = bound.trait_ref()
&& let Some(trait_did) = trait_ref.trait_def_id()
&& self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
{
true
} else {
false
}
}
}),
&mut bounds,
ty::List::empty(),
only_self_bounds,
);
debug!(?bounds);
bounds
}
/// Lower an associated item constraint from the HIR into `bounds`.
///
/// ### A Note on Binders
@ -267,7 +228,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
bounds: &mut Bounds<'tcx>,
duplicates: &mut FxIndexMap<DefId, Span>,
path_span: Span,
only_self_bounds: OnlySelfBounds,
predicate_filter: PredicateFilter,
) -> Result<(), ErrorGuaranteed> {
let tcx = self.tcx();
@ -444,21 +405,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator<Item: Debug>`
// to a bound involving a projection: `<T as Iterator>::Item: Debug`.
hir::AssocItemConstraintKind::Bound { bounds: hir_bounds } => {
// NOTE: If `only_self_bounds` is true, do NOT expand this associated type bound into
// a trait predicate, since we only want to add predicates for the `Self` type.
if !only_self_bounds.0 {
let projection_ty = projection_term
.map_bound(|projection_term| projection_term.expect_ty(self.tcx()));
// Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
// parameter to have a skipped binder.
let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
self.lower_poly_bounds(
param_ty,
hir_bounds.iter(),
bounds,
projection_ty.bound_vars(),
only_self_bounds,
);
match predicate_filter {
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {}
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
let projection_ty = projection_term
.map_bound(|projection_term| projection_term.expect_ty(self.tcx()));
// Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
// parameter to have a skipped binder.
let param_ty =
Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
self.lower_bounds(
param_ty,
hir_bounds,
bounds,
projection_ty.bound_vars(),
predicate_filter,
);
}
}
}
}
@ -516,7 +479,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty,
trait_segment,
false,
ty::BoundConstness::NotConst,
);
// SUBTLE: As noted at the end of `try_append_return_type_notation_params`

View File

@ -20,7 +20,7 @@ use tracing::{debug, instrument};
use super::HirTyLowerer;
use crate::bounds::Bounds;
use crate::hir_ty_lowering::{
GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason,
GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason,
};
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
@ -51,13 +51,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} = self.lower_poly_trait_ref(
&trait_bound.trait_ref,
trait_bound.span,
ty::BoundConstness::NotConst,
None,
ty::PredicatePolarity::Positive,
dummy_self,
&mut bounds,
// True so we don't populate `bounds` with associated type bounds, even
// though they're disallowed from object types.
OnlySelfBounds(true),
PredicateFilter::SelfOnly,
) {
potential_assoc_types.extend(cur_potential_assoc_types);
}

View File

@ -64,9 +64,6 @@ use crate::require_c_abi_if_c_variadic;
#[derive(Debug)]
pub struct GenericPathSegment(pub DefId, pub usize);
#[derive(Copy, Clone, Debug)]
pub struct OnlySelfBounds(pub bool);
#[derive(Copy, Clone, Debug)]
pub enum PredicateFilter {
/// All predicates may be implied by the trait.
@ -76,7 +73,8 @@ pub enum PredicateFilter {
SelfOnly,
/// Only traits that reference `Self: ..` and define an associated type
/// with the given ident are implied by the trait.
/// with the given ident are implied by the trait. This mode exists to
/// side-step query cycles when lowering associated types.
SelfThatDefines(Ident),
/// Only traits that reference `Self: ..` and their associated type bounds.
@ -336,14 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
def_id: DefId,
item_segment: &hir::PathSegment<'tcx>,
) -> GenericArgsRef<'tcx> {
let (args, _) = self.lower_generic_args_of_path(
span,
def_id,
&[],
item_segment,
None,
ty::BoundConstness::NotConst,
);
let (args, _) = self.lower_generic_args_of_path(span, def_id, &[], item_segment, None);
if let Some(c) = item_segment.args().constraints.first() {
prohibit_assoc_item_constraint(self, c, Some((def_id, item_segment, span)));
}
@ -392,7 +383,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
parent_args: &[ty::GenericArg<'tcx>],
segment: &hir::PathSegment<'tcx>,
self_ty: Option<Ty<'tcx>>,
constness: ty::BoundConstness,
) -> (GenericArgsRef<'tcx>, GenericArgCountResult) {
// If the type is parameterized by this region, then replace this
// region with the current anon region binding (in other words,
@ -415,7 +405,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
assert!(self_ty.is_none());
}
let mut arg_count = check_generic_arg_count(
let arg_count = check_generic_arg_count(
self,
def_id,
segment,
@ -573,16 +563,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
}
if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
&& generics.has_self
&& !tcx.is_const_trait(def_id)
{
let reported = self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
span,
modifier: constness.as_str(),
});
arg_count.correct = Err(GenericArgCountMismatch { reported, invalid_args: vec![] });
}
let mut args_ctx = GenericArgsCtxt {
lowerer: self,
@ -614,14 +594,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
parent_args: GenericArgsRef<'tcx>,
) -> GenericArgsRef<'tcx> {
debug!(?span, ?item_def_id, ?item_segment);
let (args, _) = self.lower_generic_args_of_path(
span,
item_def_id,
parent_args,
item_segment,
None,
ty::BoundConstness::NotConst,
);
let (args, _) =
self.lower_generic_args_of_path(span, item_def_id, parent_args, item_segment, None);
if let Some(c) = item_segment.args().constraints.first() {
prohibit_assoc_item_constraint(self, c, Some((item_def_id, item_segment, span)));
}
@ -647,7 +621,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty,
trait_ref.path.segments.last().unwrap(),
true,
ty::BoundConstness::NotConst,
)
}
@ -679,11 +652,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
trait_ref: &hir::TraitRef<'tcx>,
span: Span,
constness: ty::BoundConstness,
constness: Option<ty::BoundConstness>,
polarity: ty::PredicatePolarity,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
only_self_bounds: OnlySelfBounds,
predicate_filter: PredicateFilter,
) -> GenericArgCountResult {
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
let trait_segment = trait_ref.path.segments.last().unwrap();
@ -700,9 +673,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&[],
trait_segment,
Some(self_ty),
constness,
);
if let Some(constness) = constness
&& !self.tcx().is_const_trait(trait_def_id)
{
self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
span: trait_ref.path.span,
modifier: constness.as_str(),
});
}
let tcx = self.tcx();
let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
debug!(?bound_vars);
@ -720,7 +701,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span,
polarity,
constness,
only_self_bounds,
predicate_filter,
);
let mut dup_constraints = FxIndexMap::default();
@ -744,7 +725,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
bounds,
&mut dup_constraints,
constraint.span,
only_self_bounds,
predicate_filter,
);
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
}
@ -762,19 +743,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty: Ty<'tcx>,
trait_segment: &hir::PathSegment<'tcx>,
is_impl: bool,
// FIXME(effects): Move all host param things in HIR ty lowering to AST lowering.
constness: ty::BoundConstness,
) -> ty::TraitRef<'tcx> {
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
let (generic_args, _) = self.lower_generic_args_of_path(
span,
trait_def_id,
&[],
trait_segment,
Some(self_ty),
constness,
);
let (generic_args, _) =
self.lower_generic_args_of_path(span, trait_def_id, &[], trait_segment, Some(self_ty));
if let Some(c) = trait_segment.args().constraints.first() {
prohibit_assoc_item_constraint(self, c, Some((trait_def_id, trait_segment, span)));
}
@ -1542,7 +1515,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
item_segment: &hir::PathSegment<'tcx>,
constness: ty::BoundConstness,
) -> Ty<'tcx> {
let tcx = self.tcx();
@ -1555,7 +1527,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
debug!(?self_ty);
let trait_ref =
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false, constness);
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
debug!(?trait_ref);
let item_args =
@ -1918,7 +1890,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
def_id,
&path.segments[path.segments.len() - 2],
path.segments.last().unwrap(),
ty::BoundConstness::NotConst,
)
}
Res::PrimTy(prim_ty) => {
@ -2151,7 +2122,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&[],
&hir::PathSegment::invalid(),
None,
ty::BoundConstness::NotConst,
);
tcx.at(span).type_of(def_id).instantiate(tcx, args)
}

View File

@ -537,40 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
//
// This check is here because there is currently no way to express a trait bound for `FnDef` types only.
if let ty::FnDef(def_id, _args) = *arg_ty.kind() {
let fn_once_def_id =
self.tcx.require_lang_item(hir::LangItem::FnOnce, Some(span));
let fn_once_output_def_id =
self.tcx.require_lang_item(hir::LangItem::FnOnceOutput, Some(span));
if self.tcx.has_host_param(fn_once_def_id) {
let const_param: ty::GenericArg<'tcx> =
([self.tcx.consts.false_, self.tcx.consts.true_])[idx].into();
self.register_predicate(traits::Obligation::new(
self.tcx,
self.misc(span),
self.param_env,
ty::TraitRef::new(self.tcx, fn_once_def_id, [
arg_ty.into(),
fn_sig.inputs()[0].into(),
const_param,
]),
));
self.register_predicate(traits::Obligation::new(
self.tcx,
self.misc(span),
self.param_env,
ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new(
self.tcx,
fn_once_output_def_id,
[arg_ty.into(), fn_sig.inputs()[0].into(), const_param],
),
term: fn_sig.output().into(),
},
));
self.select_obligations_where_possible(|_| {});
} else if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
self.dcx().emit_err(errors::ConstSelectMustBeConst { span });
}
} else {

View File

@ -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>,

View File

@ -1487,7 +1487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
} else if self.tcx.features().generic_const_exprs {
ct.normalize(self.tcx, self.param_env)
ct.normalize_internal(self.tcx, self.param_env)
} else {
ct
}

View File

@ -1097,6 +1097,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut only_extras_so_far = errors
.peek()
.is_some_and(|first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0));
let mut prev_extra_idx = None;
let mut suggestions = vec![];
while let Some(error) = errors.next() {
only_extras_so_far &= matches!(error, Error::Extra(_));
@ -1165,11 +1166,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// fn f() {}
// - f(0, 1,)
// + f()
if only_extras_so_far
&& !errors
.peek()
.is_some_and(|next_error| matches!(next_error, Error::Extra(_)))
{
let trim_next_comma = match errors.peek() {
Some(Error::Extra(provided_idx))
if only_extras_so_far
&& provided_idx.index() > arg_idx.index() + 1 =>
// If the next Error::Extra ("next") doesn't next to current ("current"),
// fn foo(_: (), _: u32) {}
// - foo("current", (), 1u32, "next")
// + foo((), 1u32)
// If the previous error is not a `Error::Extra`, then do not trim the next comma
// - foo((), "current", 42u32, "next")
// + foo((), 42u32)
{
prev_extra_idx.map_or(true, |prev_extra_idx| {
prev_extra_idx + 1 == arg_idx.index()
})
}
// If no error left, we need to delete the next comma
None if only_extras_so_far => true,
// Not sure if other error type need to be handled as well
_ => false,
};
if trim_next_comma {
let next = provided_arg_tys
.get(arg_idx + 1)
.map(|&(_, sp)| sp)
@ -1192,6 +1211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
SuggestionText::Remove(_) => SuggestionText::Remove(true),
_ => SuggestionText::DidYouMean,
};
prev_extra_idx = Some(arg_idx.index())
}
}
Error::Missing(expected_idx) => {

View File

@ -155,7 +155,7 @@ fn typeck_with_fallback<'tcx>(
tcx.fn_sig(def_id).instantiate_identity()
};
check_abi(tcx, id, span, fn_sig.abi());
check_abi(tcx, span, fn_sig.abi());
// Compute the function signature from point of view of inside the fn.
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
@ -419,7 +419,7 @@ fn report_unexpected_variant_res(
}
}
err.multipart_suggestion_verbose(descr, suggestion, Applicability::MaybeIncorrect);
err.multipart_suggestion_verbose(descr, suggestion, Applicability::HasPlaceholders);
err
}
Res::Def(DefKind::Variant, _) if expr.is_none() => {

View File

@ -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, &param_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(

View File

@ -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,

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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)
}

View File

@ -2601,7 +2601,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init))
}
Array(ty, len) => {
if matches!(len.try_eval_target_usize(cx.tcx, cx.param_env), Some(v) if v > 0) {
if matches!(len.try_to_target_usize(cx.tcx), Some(v) if v > 0) {
// Array length known at array non-empty -- recurse.
ty_find_init_error(cx, *ty, init)
} else {

View File

@ -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)`

View File

@ -598,6 +598,7 @@ fn register_builtins(store: &mut LintStore) {
"converted into hard error, see PR #125380 \
<https://github.com/rust-lang/rust/pull/125380> for more information",
);
store.register_removed("unsupported_calling_conventions", "converted into hard error");
}
fn register_internals(store: &mut LintStore) {

View File

@ -18,6 +18,8 @@ use rustc_target::spec::abi::Abi as SpecAbi;
use tracing::debug;
use {rustc_ast as ast, rustc_hir as hir};
mod improper_ctypes;
use crate::lints::{
AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
@ -728,7 +730,6 @@ fn is_niche_optimization_candidate<'tcx>(
/// can, return the type that `ty` can be safely converted to, otherwise return `None`.
/// Currently restricted to function pointers, boxes, references, `core::num::NonZero`,
/// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
/// FIXME: This duplicates code in codegen.
pub(crate) fn repr_nullable_ptr<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@ -741,10 +742,6 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
[var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
([], [field]) | ([field], []) => field.ty(tcx, args),
([field1], [field2]) => {
if !tcx.features().result_ffi_guarantees {
return None;
}
let ty1 = field1.ty(tcx, args);
let ty2 = field2.ty(tcx, args);
@ -983,15 +980,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// Empty enums are okay... although sort of useless.
return FfiSafe;
}
if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
return FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_non_exhaustive,
help: None,
};
}
// Check for a repr() attribute to specify the size of the
// discriminant.
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
@ -1010,21 +998,23 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
};
}
use improper_ctypes::{
check_non_exhaustive_variant, non_local_and_non_exhaustive,
};
let non_local_def = non_local_and_non_exhaustive(def);
// Check the contained variants.
for variant in def.variants() {
let is_non_exhaustive = variant.is_field_list_non_exhaustive();
if is_non_exhaustive && !variant.def_id.is_local() {
return FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_non_exhaustive_variant,
help: None,
};
}
let ret = def.variants().iter().try_for_each(|variant| {
check_non_exhaustive_variant(non_local_def, variant)
.map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
match self.check_variant_for_ffi(acc, ty, def, variant, args) {
FfiSafe => (),
r => return r,
FfiSafe => ControlFlow::Continue(()),
r => ControlFlow::Break(r),
}
});
if let ControlFlow::Break(result) = ret {
return result;
}
FfiSafe

View 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()
}

View File

@ -346,7 +346,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
None
}
}
ty::Array(ty, len) => match len.try_eval_target_usize(cx.tcx, cx.param_env) {
ty::Array(ty, len) => match len.try_to_target_usize(cx.tcx) {
// If the array is empty we don't lint, to avoid false positives
Some(0) | None => None,
// If the array is definitely non-empty, we can do `#[must_use]` checking.

View File

@ -123,7 +123,6 @@ declare_lint_pass! {
UNSAFE_OP_IN_UNSAFE_FN,
UNSTABLE_NAME_COLLISIONS,
UNSTABLE_SYNTAX_PRE_EXPANSION,
UNSUPPORTED_CALLING_CONVENTIONS,
UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
UNUSED_ASSIGNMENTS,
UNUSED_ASSOCIATED_TYPE_BOUNDS,
@ -156,7 +155,7 @@ declare_lint! {
///
/// ```rust
/// #![forbid(warnings)]
/// #![deny(bad_style)]
/// #![warn(bad_style)]
///
/// fn main() {}
/// ```
@ -2667,7 +2666,6 @@ declare_lint! {
/// ### Example
///
/// ```rust
/// #![feature(strict_provenance)]
/// #![warn(fuzzy_provenance_casts)]
///
/// fn main() {
@ -2701,7 +2699,7 @@ declare_lint! {
pub FUZZY_PROVENANCE_CASTS,
Allow,
"a fuzzy integer to pointer cast is used",
@feature_gate = strict_provenance;
@feature_gate = strict_provenance_lints;
}
declare_lint! {
@ -2711,7 +2709,6 @@ declare_lint! {
/// ### Example
///
/// ```rust
/// #![feature(strict_provenance)]
/// #![warn(lossy_provenance_casts)]
///
/// fn main() {
@ -2747,7 +2744,7 @@ declare_lint! {
pub LOSSY_PROVENANCE_CASTS,
Allow,
"a lossy pointer to integer cast is used",
@feature_gate = strict_provenance;
@feature_gate = strict_provenance_lints;
}
declare_lint! {
@ -3789,53 +3786,6 @@ declare_lint! {
crate_level_only
}
declare_lint! {
/// The `unsupported_calling_conventions` lint is output whenever there is a use of the
/// `stdcall`, `fastcall`, `thiscall`, `vectorcall` calling conventions (or their unwind
/// variants) on targets that cannot meaningfully be supported for the requested target.
///
/// For example `stdcall` does not make much sense for a x86_64 or, more apparently, powerpc
/// code, because this calling convention was never specified for those targets.
///
/// Historically MSVC toolchains have fallen back to the regular C calling convention for
/// targets other than x86, but Rust doesn't really see a similar need to introduce a similar
/// hack across many more targets.
///
/// ### Example
///
/// ```rust,ignore (needs specific targets)
/// extern "stdcall" fn stdcall() {}
/// ```
///
/// This will produce:
///
/// ```text
/// warning: use of calling convention not supported on this target
/// --> $DIR/unsupported.rs:39:1
/// |
/// LL | extern "stdcall" fn stdcall() {}
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// |
/// = note: `#[warn(unsupported_calling_conventions)]` on by default
/// = warning: this was previously accepted by the compiler but is being phased out;
/// it will become a hard error in a future release!
/// = note: for more information, see issue ...
/// ```
///
/// ### Explanation
///
/// On most of the targets the behaviour of `stdcall` and similar calling conventions is not
/// defined at all, but was previously accepted due to a bug in the implementation of the
/// compiler.
pub UNSUPPORTED_CALLING_CONVENTIONS,
Warn,
"use of unsupported calling convention",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
reference: "issue #87678 <https://github.com/rust-lang/rust/issues/87678>",
};
}
declare_lint! {
/// The `unsupported_fn_ptr_calling_conventions` lint is output whenever there is a use of
/// a target dependent calling convention on a target that does not support this calling

View File

@ -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;

View File

@ -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,

View File

@ -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 {

View File

@ -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(),

View File

@ -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(),
};
}

View File

@ -56,7 +56,6 @@
#![feature(ptr_alignment_type)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![feature(strict_provenance)]
#![feature(trait_upcasting)]
#![feature(trusted_len)]
#![feature(try_blocks)]

View File

@ -1,5 +1,6 @@
use std::fmt::{self, Debug, Display, Formatter};
use either::Either;
use rustc_hir::def_id::DefId;
use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_session::RemapFileNameExt;
@ -320,8 +321,14 @@ impl<'tcx> Const<'tcx> {
Const::Ty(_, c) => {
// We want to consistently have a "clean" value for type system constants (i.e., no
// data hidden in the padding), so we always go through a valtree here.
let (ty, val) = c.eval(tcx, param_env, span)?;
Ok(tcx.valtree_to_const_val((ty, val)))
match c.eval_valtree(tcx, param_env, span) {
Ok((ty, val)) => Ok(tcx.valtree_to_const_val((ty, val))),
Err(Either::Left(_bad_ty)) => Err(tcx
.dcx()
.delayed_bug("`mir::Const::eval` called on a non-valtree-compatible type")
.into()),
Err(Either::Right(e)) => Err(e),
}
}
Const::Unevaluated(uneval, _) => {
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`

View File

@ -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()
}

View File

@ -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]

View File

@ -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,

View File

@ -55,7 +55,7 @@ impl<'tcx> PlaceTy<'tcx> {
/// `PlaceElem`, where we can just use the `Ty` that is already
/// stored inline on field projection elems.
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty)
self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty)
}
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@ -66,7 +66,6 @@ impl<'tcx> PlaceTy<'tcx> {
pub fn projection_ty_core<V, T>(
self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
elem: &ProjectionElem<V, T>,
mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>,
mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>,
@ -93,7 +92,9 @@ impl<'tcx> PlaceTy<'tcx> {
ty::Slice(..) => self.ty,
ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from),
ty::Array(inner, size) if from_end => {
let size = size.eval_target_usize(tcx, param_env);
let size = size
.try_to_target_usize(tcx)
.expect("expected subslice projection on fixed-size array");
let len = size - from - to;
Ty::new_array(tcx, *inner, len)
}

View File

@ -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 {

View File

@ -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>> {

View File

@ -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> {

View File

@ -161,9 +161,7 @@ pub enum SelectionCandidate<'tcx> {
/// Implementation of a `Fn`-family trait by one of the anonymous
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
FnPointerCandidate {
fn_host_effect: ty::Const<'tcx>,
},
FnPointerCandidate,
TraitAliasCandidate,
@ -180,9 +178,6 @@ pub enum SelectionCandidate<'tcx> {
BuiltinObjectCandidate,
BuiltinUnsizeCandidate,
/// Implementation of `const Destruct`, optionally from a custom `impl const Drop`.
ConstDestructCandidate(Option<DefId>),
}
/// The result of trait evaluation. The order is important

View File

@ -398,133 +398,65 @@ impl<'tcx> Const<'tcx> {
}
}
/// Returns the evaluated constant
#[inline]
pub fn eval(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
span: Span,
) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> {
self.eval_valtree(tcx, param_env, span).map_err(|err| {
match err {
Either::Right(err) => err,
Either::Left(_bad_ty) => {
// This can happen when we run on ill-typed code.
let e = tcx.dcx().span_delayed_bug(
span,
"`ty::Const::eval` called on a non-valtree-compatible type",
);
e.into()
}
}
})
}
/// Normalizes the constant to a value or an error if possible.
#[inline]
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
match self.eval(tcx, param_env, DUMMY_SP) {
pub fn normalize_internal(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
match self.eval_valtree(tcx, param_env, DUMMY_SP) {
Ok((ty, val)) => Self::new_value(tcx, val, ty),
Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into()),
Err(ErrorHandled::TooGeneric(_span)) => self,
Err(Either::Left(_bad_ty)) => {
// This can happen when we run on ill-typed code.
Self::new_error(
tcx,
tcx.dcx()
.delayed_bug("`ty::Const::eval` called on a non-valtree-compatible type"),
)
}
Err(Either::Right(ErrorHandled::Reported(r, _span))) => Self::new_error(tcx, r.into()),
Err(Either::Right(ErrorHandled::TooGeneric(_span))) => self,
}
}
#[inline]
pub fn try_eval_scalar(
self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Option<(Ty<'tcx>, Scalar)> {
let (ty, val) = self.eval(tcx, param_env, DUMMY_SP).ok()?;
let val = val.try_to_scalar()?;
Some((ty, val))
}
#[inline]
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
/// contains const generic parameters or pointers).
pub fn try_eval_scalar_int(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> Option<(Ty<'tcx>, ScalarInt)> {
let (ty, scalar) = self.try_eval_scalar(tcx, param_env)?;
let val = scalar.try_to_scalar_int().ok()?;
Some((ty, val))
}
#[inline]
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
/// contains const generic parameters or pointers).
pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> {
let (ty, scalar) = self.try_eval_scalar_int(tcx, param_env)?;
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
// if `ty` does not depend on generic parameters, use an empty param_env
Some(scalar.to_bits(size))
}
#[inline]
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 {
self.try_eval_bits(tcx, param_env)
.unwrap_or_else(|| bug!("failed to evalate {:#?} to bits", self))
}
#[inline]
pub fn try_eval_target_usize(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> Option<u64> {
let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?;
Some(scalar.to_target_usize(tcx))
}
#[inline]
pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?;
scalar.try_into().ok()
}
#[inline]
/// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
self.try_eval_target_usize(tcx, param_env)
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
}
/// Panics if self.kind != ty::ConstKind::Value
pub fn to_valtree(self) -> ty::ValTree<'tcx> {
pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) {
match self.kind() {
ty::ConstKind::Value(_, valtree) => valtree,
ty::ConstKind::Value(ty, valtree) => (valtree, ty),
_ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
}
}
/// Attempts to convert to a `ValTree`
pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> {
pub fn try_to_valtree(self) -> Option<(ty::ValTree<'tcx>, Ty<'tcx>)> {
match self.kind() {
ty::ConstKind::Value(_, valtree) => Some(valtree),
ty::ConstKind::Value(ty, valtree) => Some((valtree, ty)),
_ => None,
}
}
#[inline]
pub fn try_to_scalar(self) -> Option<Scalar> {
self.try_to_valtree()?.try_to_scalar()
pub fn try_to_scalar(self) -> Option<(Scalar, Ty<'tcx>)> {
let (valtree, ty) = self.try_to_valtree()?;
Some((valtree.try_to_scalar()?, ty))
}
pub fn try_to_bool(self) -> Option<bool> {
self.try_to_valtree()?.try_to_scalar_int()?.try_to_bool().ok()
self.try_to_valtree()?.0.try_to_scalar_int()?.try_to_bool().ok()
}
#[inline]
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
self.try_to_valtree()?.try_to_target_usize(tcx)
self.try_to_valtree()?.0.try_to_target_usize(tcx)
}
#[inline]
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
/// contains const generic parameters or pointers).
pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> {
let (scalar, ty) = self.try_to_scalar()?;
let scalar = scalar.try_to_scalar_int().ok()?;
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
// if `ty` does not depend on generic parameters, use an empty param_env
Some(scalar.to_bits(size))
}
pub fn is_ct_infer(self) -> bool {

View File

@ -85,7 +85,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
match self {
Self::False => Ok(false),
Self::True => Ok(true),
Self::ConstIsZero(const_) => match const_.try_eval_target_usize(tcx, param_env) {
Self::ConstIsZero(const_) => match const_.try_to_target_usize(tcx) {
None | Some(0) => Ok(true),
Some(1..) => Ok(false),
},

View File

@ -397,7 +397,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
}
}
ty::Array(inner, len) if tcx.features().transmute_generic_consts => {
let len_eval = len.try_eval_target_usize(tcx, param_env);
let len_eval = len.try_to_target_usize(tcx);
if len_eval == Some(0) {
return Ok(SizeSkeleton::Known(Size::from_bytes(0), None));
}

View File

@ -1956,7 +1956,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
define_scoped_cx!(self);
match constness {
ty::BoundConstness::NotConst => {}
ty::BoundConstness::Const => {
p!("const ");
}
@ -2948,7 +2947,10 @@ impl<'tcx> ty::TraitPredicate<'tcx> {
}
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
pub struct TraitPredPrintWithBoundConstness<'tcx>(ty::TraitPredicate<'tcx>, ty::BoundConstness);
pub struct TraitPredPrintWithBoundConstness<'tcx>(
ty::TraitPredicate<'tcx>,
Option<ty::BoundConstness>,
);
impl<'tcx> fmt::Debug for TraitPredPrintWithBoundConstness<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -2966,7 +2968,7 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> {
fn print_with_bound_constness(
self,
constness: ty::BoundConstness,
constness: Option<ty::BoundConstness>,
) -> ty::Binder<'tcx, TraitPredPrintWithBoundConstness<'tcx>> {
self.map_bound(|trait_pred| TraitPredPrintWithBoundConstness(trait_pred, constness))
}
@ -3206,7 +3208,9 @@ define_print_and_forward_display! {
TraitPredPrintWithBoundConstness<'tcx> {
p!(print(self.0.trait_ref.self_ty()), ": ");
p!(pretty_print_bound_constness(self.1));
if let Some(constness) = self.1 {
p!(pretty_print_bound_constness(constness));
}
if let ty::PredicatePolarity::Negative = self.0.polarity {
p!("!");
}

View File

@ -1117,7 +1117,12 @@ impl<'tcx> Ty<'tcx> {
// The way we evaluate the `N` in `[T; N]` here only works since we use
// `simd_size_and_type` post-monomorphization. It will probably start to ICE
// if we use it in generic code. See the `simd-array-trait` ui test.
(f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty)
(
f0_len
.try_to_target_usize(tcx)
.expect("expected SIMD field to have definite array size"),
*f0_elem_ty,
)
}
#[inline]

View File

@ -907,24 +907,6 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
/// Constructs generic args for an item, optionally appending a const effect param type
pub fn with_opt_host_effect_param(
self,
caller_def_id: LocalDefId,
callee_def_id: DefId,
args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
) -> ty::GenericArgsRef<'tcx> {
let generics = self.generics_of(callee_def_id);
assert_eq!(generics.parent, None);
let opt_const_param = generics
.host_effect_index
.is_some()
.then(|| ty::GenericArg::from(self.expected_host_effect_param_for_body(caller_def_id)));
self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param))
}
/// Expand any [weak alias types][weak] contained within the given `value`.
///
/// This should be used over other normalization routines in situations where

View File

@ -454,12 +454,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
};
let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
let method = trait_method(
self.tcx,
eq_def_id,
sym::eq,
self.tcx.with_opt_host_effect_param(self.def_id, eq_def_id, [compare_ty, compare_ty]),
);
let method = trait_method(self.tcx, eq_def_id, sym::eq, [compare_ty, compare_ty]);
let bool_ty = self.tcx.types.bool;
let eq_result = self.temp(bool_ty, source_info.span);

View File

@ -43,7 +43,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
struct ConstToPat<'tcx> {
id: hir::HirId,
span: Span,
param_env: ty::ParamEnv<'tcx>,
@ -62,7 +61,6 @@ impl<'tcx> ConstToPat<'tcx> {
) -> Self {
trace!(?pat_ctxt.typeck_results.hir_owner);
ConstToPat {
id,
span,
infcx,
param_env: pat_ctxt.param_env,
@ -149,15 +147,7 @@ impl<'tcx> ConstToPat<'tcx> {
tcx,
ObligationCause::dummy(),
self.param_env,
ty::TraitRef::new_from_args(
tcx,
partial_eq_trait_id,
tcx.with_opt_host_effect_param(
tcx.hir().enclosing_body_owner(self.id),
partial_eq_trait_id,
[ty, ty],
),
),
ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]),
);
// This *could* accept a type that isn't actually `PartialEq`, because region bounds get

View File

@ -863,7 +863,7 @@ where
ty::Adt(def, args) => self.open_drop_for_adt(*def, args),
ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
ty::Array(ety, size) => {
let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env());
let size = size.try_to_target_usize(self.tcx());
self.open_drop_for_array(*ety, size)
}
ty::Slice(ety) => self.drop_loop_pair(*ety),

View File

@ -18,18 +18,12 @@ struct MoveDataBuilder<'a, 'tcx, F> {
body: &'a Body<'tcx>,
loc: Location,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
data: MoveData<'tcx>,
filter: F,
}
impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
fn new(
body: &'a Body<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
filter: F,
) -> Self {
fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, filter: F) -> Self {
let mut move_paths = IndexVec::new();
let mut path_map = IndexVec::new();
let mut init_path_map = IndexVec::new();
@ -59,7 +53,6 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
body,
loc: Location::START,
tcx,
param_env,
data: MoveData {
moves: IndexVec::new(),
loc_map: LocationMap::new(body),
@ -308,10 +301,9 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
pub(super) fn gather_moves<'tcx>(
body: &Body<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
filter: impl Fn(Ty<'tcx>) -> bool,
) -> MoveData<'tcx> {
let mut builder = MoveDataBuilder::new(body, tcx, param_env, filter);
let mut builder = MoveDataBuilder::new(body, tcx, filter);
builder.gather_args();
@ -550,7 +542,9 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
};
let base_ty = base_place.ty(self.body, self.tcx).ty;
let len: u64 = match base_ty.kind() {
ty::Array(_, size) => size.eval_target_usize(self.tcx, self.param_env),
ty::Array(_, size) => size
.try_to_target_usize(self.tcx)
.expect("expected subslice projection on fixed-size array"),
_ => bug!("from_end: false slice pattern of non-array type"),
};
for offset in from..to {

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