Auto merge of #2944 - oli-obk:rustup, r=oli-obk

Rustup
This commit is contained in:
bors 2023-06-28 07:13:12 +00:00
commit 984d29d260
491 changed files with 4493 additions and 2741 deletions

View File

@ -6,3 +6,6 @@ contact_links:
- name: Feature Request
url: https://internals.rust-lang.org/
about: Please discuss language feature requests on the internals forum.
- name: Clippy Bug
url: https://github.com/rust-lang/rust-clippy/issues/new/choose
about: Please report Clippy bugs such as false positives in the Clippy repo.

View File

@ -30,10 +30,11 @@ permissions:
defaults:
run:
shell: bash
concurrency:
group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}"
cancel-in-progress: true
jobs:
pr:
permissions:
actions: write
name: "PR - ${{ matrix.name }}"
env:
CI_JOB_NAME: "${{ matrix.name }}"
@ -84,11 +85,6 @@ jobs:
- name: ensure the channel matches the target branch
run: src/ci/scripts/verify-channel.sh
if: success() && !env.SKIP_JOB
- name: configure GitHub Actions to kill the build when outdated
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
@ -162,8 +158,6 @@ jobs:
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
auto:
permissions:
actions: write
name: "auto - ${{ matrix.name }}"
env:
CI_JOB_NAME: "${{ matrix.name }}"
@ -496,11 +490,6 @@ jobs:
- name: ensure the channel matches the target branch
run: src/ci/scripts/verify-channel.sh
if: success() && !env.SKIP_JOB
- name: configure GitHub Actions to kill the build when outdated
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
@ -574,8 +563,6 @@ jobs:
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
try:
permissions:
actions: write
name: "try - ${{ matrix.name }}"
env:
DIST_TRY_BUILD: 1
@ -623,11 +610,6 @@ jobs:
- name: ensure the channel matches the target branch
run: src/ci/scripts/verify-channel.sh
if: success() && !env.SKIP_JOB
- name: configure GitHub Actions to kill the build when outdated
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB

View File

@ -25,6 +25,7 @@ env:
jobs:
not-waiting-on-bors:
if: github.repository_owner == 'rust-lang'
name: skip if S-waiting-on-bors
runs-on: ubuntu-latest
steps:
@ -43,6 +44,7 @@ jobs:
fi
update:
if: github.repository_owner == 'rust-lang'
name: update dependencies
needs: not-waiting-on-bors
runs-on: ubuntu-latest
@ -76,6 +78,7 @@ jobs:
retention-days: 1
pr:
if: github.repository_owner == 'rust-lang'
name: amend PR
needs: update
runs-on: ubuntu-latest

View File

@ -480,23 +480,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "clap"
version = "3.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
dependencies = [
"atty",
"bitflags",
"clap_derive 3.2.18",
"clap_lex 0.2.2",
"indexmap",
"once_cell",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap"
version = "4.2.1"
@ -504,7 +487,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3"
dependencies = [
"clap_builder",
"clap_derive 4.2.0",
"clap_derive",
"once_cell",
]
@ -517,7 +500,7 @@ dependencies = [
"anstream",
"anstyle",
"bitflags",
"clap_lex 0.4.1",
"clap_lex",
"once_cell",
"strsim",
"terminal_size",
@ -529,20 +512,7 @@ version = "4.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
dependencies = [
"clap 4.2.1",
]
[[package]]
name = "clap_derive"
version = "3.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 1.0.102",
"clap",
]
[[package]]
@ -557,15 +527,6 @@ dependencies = [
"syn 2.0.8",
]
[[package]]
name = "clap_lex"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5538cd660450ebeb4234cfecf8f2284b844ffc4c50531e66d584ad5b91293613"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "clap_lex"
version = "0.4.1"
@ -576,7 +537,7 @@ checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
name = "clippy"
version = "0.1.72"
dependencies = [
"clap 4.2.1",
"clap",
"clippy_lints",
"clippy_utils",
"compiletest_rs",
@ -605,7 +566,7 @@ name = "clippy_dev"
version = "0.0.1"
dependencies = [
"aho-corasick",
"clap 4.2.1",
"clap",
"indoc",
"itertools",
"opener",
@ -1749,7 +1710,7 @@ name = "installer"
version = "0.0.0"
dependencies = [
"anyhow",
"clap 3.2.20",
"clap",
"flate2",
"num_cpus",
"rayon",
@ -1869,7 +1830,7 @@ name = "jsondoclint"
version = "0.1.0"
dependencies = [
"anyhow",
"clap 4.2.1",
"clap",
"fs-err",
"rustc-hash",
"rustdoc-json-types",
@ -2086,7 +2047,7 @@ dependencies = [
"ammonia",
"anyhow",
"chrono",
"clap 4.2.1",
"clap",
"clap_complete",
"elasticlunr-rs",
"env_logger 0.10.0",
@ -2370,12 +2331,6 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
[[package]]
name = "owo-colors"
version = "3.5.0"
@ -2617,30 +2572,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.102",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
@ -2897,7 +2828,7 @@ dependencies = [
name = "rustbook"
version = "0.1.0"
dependencies = [
"clap 4.2.1",
"clap",
"env_logger 0.10.0",
"mdbook",
]
@ -4346,7 +4277,7 @@ dependencies = [
"anyhow",
"bytecount",
"cargo_metadata",
"clap 4.2.1",
"clap",
"diff",
"dirs",
"env_logger 0.10.0",
@ -4874,12 +4805,6 @@ dependencies = [
"term",
]
[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]]
name = "thin-vec"
version = "0.2.12"

View File

@ -33,24 +33,13 @@ format:
```
This is how the documentation and examples assume you are running `x.py`.
Some alternative ways are:
```sh
# On a Unix shell if you don't have the necessary `python3` command
./x <subcommand> [flags]
# On the Windows Command Prompt (if .py files are configured to run Python)
x.py <subcommand> [flags]
# You can also run Python yourself, e.g.:
python x.py <subcommand> [flags]
```
See the [rustc dev guide][rustcguidebuild] if this does not work on your platform.
More information about `x.py` can be found by running it with the `--help` flag
or reading the [rustc dev guide][rustcguidebuild].
[gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.html
[rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html
[rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#what-is-xpy
### Dependencies

View File

@ -277,9 +277,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
ExprKind::Become(sub_expr) => {
let sub_expr = self.lower_expr(sub_expr);
// FIXME(explicit_tail_calls): Use `hir::ExprKind::Become` once we implemented it
hir::ExprKind::Ret(Some(sub_expr))
hir::ExprKind::Become(sub_expr)
}
ExprKind::InlineAsm(asm) => {
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))

View File

@ -623,13 +623,12 @@ impl<'a> AstValidator<'a> {
fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
// FIXME(davidtwco): This is a hack to detect macros which produce spans of the
// call site which do not have a macro backtrace. See #61963.
let is_macro_callsite = self
if self
.session
.source_map()
.span_to_snippet(span)
.map(|snippet| snippet.starts_with("#["))
.unwrap_or(true);
if !is_macro_callsite {
.is_ok_and(|snippet| !snippet.starts_with("#["))
{
self.lint_buffer.buffer_lint_with_diagnostic(
MISSING_ABI,
id,

View File

@ -77,13 +77,6 @@ pub struct ForbiddenLifetimeBound {
pub spans: Vec<Span>,
}
#[derive(Diagnostic)]
#[diag(ast_passes_forbidden_non_lifetime_param)]
pub struct ForbiddenNonLifetimeParam {
#[primary_span]
pub spans: Vec<Span>,
}
#[derive(Diagnostic)]
#[diag(ast_passes_fn_param_too_many)]
pub struct FnParamTooMany {

View File

@ -678,8 +678,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let tcx = self.infcx.tcx;
// Find out if the predicates show that the type is a Fn or FnMut
let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| {
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = pred.kind().skip_binder()
let find_fn_kind_from_did = |(pred, _): (ty::Clause<'tcx>, _)| {
if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
&& pred.self_ty() == ty
{
if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
@ -705,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
.explicit_item_bounds(def_id)
.subst_iter_copied(tcx, substs)
.find_map(|(clause, span)| find_fn_kind_from_did((clause.as_predicate(), span))),
.find_map(|(clause, span)| find_fn_kind_from_did((clause, span))),
ty::Closure(_, substs) => match substs.as_closure().kind() {
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),

View File

@ -123,13 +123,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
item_msg = access_place_desc;
debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
debug_assert!(is_closure_or_generator(
Place::ty_from(
the_place_err.local,
the_place_err.projection,
self.body,
self.infcx.tcx
)
.ty
the_place_err.ty(self.body, self.infcx.tcx).ty
));
reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() {

View File

@ -928,7 +928,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
fn any_param_predicate_mentions(
&self,
predicates: &[ty::Predicate<'tcx>],
clauses: &[ty::Clause<'tcx>],
ty: Ty<'tcx>,
region: ty::EarlyBoundRegion,
) -> bool {
@ -937,10 +937,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
&& let ty::Param(_) = ty.kind()
{
predicates.iter().any(|pred| {
clauses.iter().any(|pred| {
match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) if data.self_ty() == ty => {}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) if data.projection_ty.self_ty() == ty => {}
ty::ClauseKind::Trait(data) if data.self_ty() == ty => {}
ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
_ => return false,
}
tcx.any_free_region_meets(pred, |r| {

View File

@ -46,11 +46,9 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
}
}
for (i, elem) in self.projection.iter().enumerate() {
let proj_base = &self.projection[..i];
for (i, (proj_base, elem)) in self.iter_projections().enumerate() {
if elem == ProjectionElem::Deref {
let ty = Place::ty_from(self.local, proj_base, body, tcx).ty;
let ty = proj_base.ty(body, tcx).ty;
match ty.kind() {
ty::Ref(_, _, hir::Mutability::Not) if i == 0 => {
// For references to thread-local statics, we do need

View File

@ -137,13 +137,11 @@ fn place_components_conflict<'tcx>(
}
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
for (i, (borrow_c, &access_c)) in
iter::zip(borrow_place.projection, access_place.projection).enumerate()
for ((borrow_place, borrow_c), &access_c) in
iter::zip(borrow_place.iter_projections(), access_place.projection)
{
debug!(?borrow_c, ?access_c);
let borrow_proj_base = &borrow_place.projection[..i];
// Borrow and access path both have more components.
//
// Examples:
@ -156,15 +154,7 @@ fn place_components_conflict<'tcx>(
// check whether the components being borrowed vs
// accessed are disjoint (as in the second example,
// but not the first).
match place_projection_conflict(
tcx,
body,
borrow_local,
borrow_proj_base,
borrow_c,
access_c,
bias,
) {
match place_projection_conflict(tcx, body, borrow_place, borrow_c, access_c, bias) {
Overlap::Arbitrary => {
// We have encountered different fields of potentially
// the same union - the borrow now partially overlaps.
@ -195,8 +185,7 @@ fn place_components_conflict<'tcx>(
}
if borrow_place.projection.len() > access_place.projection.len() {
for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate()
{
for (base, elem) in borrow_place.iter_projections().skip(access_place.projection.len()) {
// Borrow path is longer than the access path. Examples:
//
// - borrow of `a.b.c`, access to `a.b`
@ -205,8 +194,7 @@ fn place_components_conflict<'tcx>(
// our place. This is a conflict if that is a part our
// access cares about.
let proj_base = &borrow_place.projection[..access_place.projection.len() + i];
let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty;
let base_ty = base.ty(body, tcx).ty;
match (elem, &base_ty.kind(), access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
@ -310,8 +298,7 @@ fn place_base_conflict(l1: Local, l2: Local) -> Overlap {
fn place_projection_conflict<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
pi1_local: Local,
pi1_proj_base: &[PlaceElem<'tcx>],
pi1: PlaceRef<'tcx>,
pi1_elem: PlaceElem<'tcx>,
pi2_elem: PlaceElem<'tcx>,
bias: PlaceConflictBias,
@ -333,7 +320,7 @@ fn place_projection_conflict<'tcx>(
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
Overlap::EqualOrDisjoint
} else {
let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty;
let ty = pi1.ty(body, tcx).ty;
if ty.is_union() {
// Different fields of a union, we are basically stuck.
debug!("place_element_conflict: STUCK-UNION");

View File

@ -50,7 +50,6 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::ResultsCursor;
use crate::renumber::RegionCtxt;
use crate::session_diagnostics::MoveUnsized;
use crate::{
borrow_set::BorrowSet,
@ -1040,9 +1039,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.collect();
let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| {
self.infcx.next_nll_region_var(
self.infcx.next_nll_region_var_in_universe(
NllRegionVariableOrigin::Existential { from_forall: false },
|| RegionCtxt::Unknown,
ty::UniverseIndex::ROOT,
)
});
@ -2503,7 +2502,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
location, borrow_region, borrowed_place
);
let mut cursor = borrowed_place.projection.as_ref();
let tcx = self.infcx.tcx;
let field = path_utils::is_upvar_field_projection(
tcx,
@ -2517,14 +2515,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::Boring
};
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
for (base, elem) in borrowed_place.as_ref().iter_projections().rev() {
debug!("add_reborrow_constraint - iteration {:?}", elem);
match elem {
ProjectionElem::Deref => {
let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty;
let base_ty = base.ty(body, tcx).ty;
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
match base_ty.kind() {

View File

@ -8,7 +8,7 @@ use rustc_feature::AttributeTemplate;
use rustc_parse::validate_attr;
use rustc_session::Session;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_span::{ErrorGuaranteed, Span};
pub(crate) struct Expander(pub bool);
@ -22,7 +22,7 @@ impl MultiItemModifier for Expander {
_: bool,
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
let sess = ecx.sess;
if report_bad_target(sess, &item, span) {
if report_bad_target(sess, &item, span).is_err() {
// We don't want to pass inappropriate targets to derive macros to avoid
// follow up errors, all other errors below are recoverable.
return ExpandResult::Ready(vec![item]);
@ -103,7 +103,11 @@ fn dummy_annotatable() -> Annotatable {
})
}
fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
fn report_bad_target(
sess: &Session,
item: &Annotatable,
span: Span,
) -> Result<(), ErrorGuaranteed> {
let item_kind = match item {
Annotatable::Item(item) => Some(&item.kind),
Annotatable::Stmt(stmt) => match &stmt.kind {
@ -116,9 +120,9 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
let bad_target =
!matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)));
if bad_target {
sess.emit_err(errors::BadDeriveTarget { span, item: item.span() });
return Err(sess.emit_err(errors::BadDeriveTarget { span, item: item.span() }));
}
bad_target
Ok(())
}
fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) {

View File

@ -8,7 +8,7 @@ use rustc_ast_pretty::pprust;
use rustc_errors::Applicability;
use rustc_expand::base::*;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{FileNameDisplayPreference, Span};
use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span};
use std::iter;
use thin_vec::{thin_vec, ThinVec};
@ -128,12 +128,15 @@ pub fn expand_test_or_bench(
};
};
// has_*_signature will report any errors in the type so compilation
// check_*_signature will report any errors in the type so compilation
// will fail. We shouldn't try to expand in this case because the errors
// would be spurious.
if (!is_bench && !has_test_signature(cx, &item))
|| (is_bench && !has_bench_signature(cx, &item))
{
let check_result = if is_bench {
check_bench_signature(cx, &item, &fn_)
} else {
check_test_signature(cx, &item, &fn_)
};
if check_result.is_err() {
return if is_stmt {
vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))]
} else {
@ -523,72 +526,62 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType {
}
}
fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
fn check_test_signature(
cx: &ExtCtxt<'_>,
i: &ast::Item,
f: &ast::Fn,
) -> Result<(), ErrorGuaranteed> {
let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
let sd = &cx.sess.parse_sess.span_diagnostic;
match &i.kind {
ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => {
if let ast::Unsafe::Yes(span) = sig.header.unsafety {
sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" });
return false;
if let ast::Unsafe::Yes(span) = f.sig.header.unsafety {
return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
}
if let ast::Async::Yes { span, .. } = sig.header.asyncness {
sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" });
return false;
if let ast::Async::Yes { span, .. } = f.sig.header.asyncness {
return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" }));
}
// If the termination trait is active, the compiler will check that the output
// type implements the `Termination` trait as `libtest` enforces that.
let has_output = match &sig.decl.output {
let has_output = match &f.sig.decl.output {
ast::FnRetTy::Default(..) => false,
ast::FnRetTy::Ty(t) if t.kind.is_unit() => false,
_ => true,
};
if !sig.decl.inputs.is_empty() {
sd.span_err(i.span, "functions used as tests can not have any arguments");
return false;
if !f.sig.decl.inputs.is_empty() {
return Err(sd.span_err(i.span, "functions used as tests can not have any arguments"));
}
if has_should_panic_attr && has_output {
sd.span_err(i.span, "functions using `#[should_panic]` must return `()`");
return false;
return Err(sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"));
}
if generics.params.iter().any(|param| !matches!(param.kind, GenericParamKind::Lifetime))
{
sd.span_err(
if f.generics.params.iter().any(|param| !matches!(param.kind, GenericParamKind::Lifetime)) {
return Err(sd.span_err(
i.span,
"functions used as tests can not have any non-lifetime generic parameters",
);
return false;
));
}
true
}
_ => {
// should be unreachable because `is_test_fn_item` should catch all non-fn items
debug_assert!(false);
false
}
}
Ok(())
}
fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
let has_sig = match &i.kind {
fn check_bench_signature(
cx: &ExtCtxt<'_>,
i: &ast::Item,
f: &ast::Fn,
) -> Result<(), ErrorGuaranteed> {
// N.B., inadequate check, but we're running
// well before resolve, can't get too deep.
ast::ItemKind::Fn(box ast::Fn { sig, .. }) => sig.decl.inputs.len() == 1,
_ => false,
};
if !has_sig {
cx.sess.parse_sess.span_diagnostic.span_err(
if f.sig.decl.inputs.len() != 1 {
return Err(cx.sess.parse_sess.span_diagnostic.span_err(
i.span,
"functions used as benches must have \
signature `fn(&mut Bencher) -> impl Termination`",
);
));
}
has_sig
Ok(())
}

View File

@ -225,10 +225,10 @@ pub(crate) fn write_ir_file(
let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file));
if let Err(err) = res {
// Using early_warn as no Session is available here
rustc_session::early_warn(
let handler = rustc_session::EarlyErrorHandler::new(
rustc_session::config::ErrorOutputType::default(),
format!("error writing ir file: {}", err),
);
handler.early_warn(format!("error writing ir file: {}", err));
}
}

View File

@ -572,8 +572,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
) {
let zero = self.const_usize(0);
let count = self.const_usize(count);
let start = dest.project_index(self, zero).llval;
let end = dest.project_index(self, count).llval;
let header_bb = self.append_sibling_block("repeat_loop_header");
let body_bb = self.append_sibling_block("repeat_loop_body");
@ -582,24 +580,18 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
self.br(header_bb);
let mut header_bx = Self::build(self.cx, header_bb);
let current = header_bx.phi(self.val_ty(start), &[start], &[self.llbb()]);
let i = header_bx.phi(self.val_ty(zero), &[zero], &[self.llbb()]);
let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end);
let keep_going = header_bx.icmp(IntPredicate::IntULT, i, count);
header_bx.cond_br(keep_going, body_bb, next_bb);
let mut body_bx = Self::build(self.cx, body_bb);
let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
cg_elem
.val
.store(&mut body_bx, PlaceRef::new_sized_aligned(current, cg_elem.layout, align));
let dest_elem = dest.project_index(&mut body_bx, i);
cg_elem.val.store(&mut body_bx, dest_elem);
let next = body_bx.inbounds_gep(
self.backend_type(cg_elem.layout),
current,
&[self.const_usize(1)],
);
let next = body_bx.unchecked_uadd(i, self.const_usize(1));
body_bx.br(header_bb);
header_bx.add_incoming_to_phi(current, next, body_bb);
header_bx.add_incoming_to_phi(i, next, body_bb);
*self = Self::build(self.cx, next_bb);
}

View File

@ -4,6 +4,7 @@
#![feature(if_let_guard)]
#![feature(int_roundings)]
#![feature(let_chains)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(strict_provenance)]
#![feature(try_blocks)]

View File

@ -1729,7 +1729,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
IndirectOperand(tmp, index) => {
let op = bx.load_operand(tmp);
tmp.storage_dead(bx);
self.locals[index] = LocalRef::Operand(op);
self.overwrite_local(index, LocalRef::Operand(op));
self.debug_introduce_local(bx, index);
}
DirectOperand(index) => {
@ -1744,7 +1744,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else {
OperandRef::from_immediate_or_packed_pair(bx, llval, ret_abi.layout)
};
self.locals[index] = LocalRef::Operand(op);
self.overwrite_local(index, LocalRef::Operand(op));
self.debug_introduce_local(bx, index);
}
}

View File

@ -248,7 +248,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
fn spill_operand_to_stack(
operand: &OperandRef<'tcx, Bx::Value>,
operand: OperandRef<'tcx, Bx::Value>,
name: Option<String>,
bx: &mut Bx,
) -> PlaceRef<'tcx, Bx::Value> {
@ -375,7 +375,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return;
}
Self::spill_operand_to_stack(operand, name, bx)
Self::spill_operand_to_stack(*operand, name, bx)
}
LocalRef::Place(place) => *place,
@ -550,7 +550,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
self.set_debug_loc(bx, var.source_info);
let base = Self::spill_operand_to_stack(
&operand,
operand,
Some(var.name.to_string()),
bx,
);

View File

@ -0,0 +1,75 @@
//! Locals are in a private module as updating `LocalRef::Operand` has to
//! be careful wrt to subtyping. To deal with this we only allow updates by using
//! `FunctionCx::overwrite_local` which handles it automatically.
use crate::mir::{FunctionCx, LocalRef};
use crate::traits::BuilderMethods;
use rustc_index::IndexVec;
use rustc_middle::mir;
use rustc_middle::ty::print::with_no_trimmed_paths;
use std::ops::{Index, IndexMut};
pub(super) struct Locals<'tcx, V> {
values: IndexVec<mir::Local, LocalRef<'tcx, V>>,
}
impl<'tcx, V> Index<mir::Local> for Locals<'tcx, V> {
type Output = LocalRef<'tcx, V>;
#[inline]
fn index(&self, index: mir::Local) -> &LocalRef<'tcx, V> {
&self.values[index]
}
}
/// To mutate locals, use `FunctionCx::overwrite_local` instead.
impl<'tcx, V, Idx: ?Sized> !IndexMut<Idx> for Locals<'tcx, V> {}
impl<'tcx, V> Locals<'tcx, V> {
pub(super) fn empty() -> Locals<'tcx, V> {
Locals { values: IndexVec::default() }
}
pub(super) fn indices(&self) -> impl DoubleEndedIterator<Item = mir::Local> + Clone + 'tcx {
self.values.indices()
}
}
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub(super) fn initialize_locals(&mut self, values: Vec<LocalRef<'tcx, Bx::Value>>) {
assert!(self.locals.values.is_empty());
for (local, value) in values.into_iter().enumerate() {
match value {
LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (),
LocalRef::Operand(op) => {
let local = mir::Local::from_usize(local);
let expected_ty = self.monomorphize(self.mir.local_decls[local].ty);
assert_eq!(expected_ty, op.layout.ty, "unexpected initial operand type");
}
}
self.locals.values.push(value);
}
}
pub(super) fn overwrite_local(
&mut self,
local: mir::Local,
mut value: LocalRef<'tcx, Bx::Value>,
) {
match value {
LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (),
LocalRef::Operand(ref mut op) => {
let local_ty = self.monomorphize(self.mir.local_decls[local].ty);
if local_ty != op.layout.ty {
// FIXME(#112651): This can be changed to an ICE afterwards.
debug!("updating type of operand due to subtyping");
with_no_trimmed_paths!(debug!(?op.layout.ty));
with_no_trimmed_paths!(debug!(?local_ty));
op.layout.ty = local_ty;
}
}
};
self.locals.values[local] = value;
}
}

View File

@ -1,21 +1,31 @@
use crate::base;
use crate::traits::*;
use rustc_index::bit_set::BitSet;
use rustc_index::IndexVec;
use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::mir::traversal;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_target::abi::call::{FnAbi, PassMode};
use std::iter;
use rustc_index::bit_set::BitSet;
use rustc_index::IndexVec;
mod analyze;
mod block;
pub mod constant;
pub mod coverageinfo;
pub mod debuginfo;
mod intrinsic;
mod locals;
pub mod operand;
pub mod place;
mod rvalue;
mod statement;
use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
use self::place::PlaceRef;
use rustc_middle::mir::traversal;
use self::operand::{OperandRef, OperandValue};
use self::place::PlaceRef;
// Used for tracking the state of generated basic blocks.
enum CachedLlbb<T> {
@ -91,7 +101,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
///
/// Avoiding allocs can also be important for certain intrinsics,
/// notably `expect`.
locals: IndexVec<mir::Local, LocalRef<'tcx, Bx::Value>>,
locals: locals::Locals<'tcx, Bx::Value>,
/// All `VarDebugInfo` from the MIR body, partitioned by `Local`.
/// This is `None` if no var`#[non_exhaustive]`iable debuginfo/names are needed.
@ -192,7 +202,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
cleanup_kinds,
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
locals: IndexVec::new(),
locals: locals::Locals::empty(),
debug_context,
per_local_var_debug_info: None,
caller_location: None,
@ -223,7 +233,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let memory_locals = analyze::non_ssa_locals(&fx);
// Allocate variable and temp allocas
fx.locals = {
let local_values = {
let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals);
let mut allocate_local = |local| {
@ -256,6 +266,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
.chain(mir.vars_and_temps_iter().map(allocate_local))
.collect()
};
fx.initialize_locals(local_values);
// Apply debuginfo to the newly allocated locals.
fx.debug_introduce_locals(&mut start_bx);
@ -289,14 +300,13 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
.enumerate()
.map(|(arg_index, local)| {
let arg_decl = &mir.local_decls[local];
let arg_ty = fx.monomorphize(arg_decl.ty);
if Some(local) == mir.spread_arg {
// This argument (e.g., the last argument in the "rust-call" ABI)
// is a tuple that was spread at the ABI level and now we have
// to reconstruct it into a tuple local variable, from multiple
// individual LLVM function arguments.
let arg_ty = fx.monomorphize(arg_decl.ty);
let ty::Tuple(tupled_arg_tys) = arg_ty.kind() else {
bug!("spread argument isn't a tuple?!");
};
@ -331,8 +341,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}
if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() {
let arg_ty = fx.monomorphize(arg_decl.ty);
let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
bx.va_start(va_list.llval);
@ -429,14 +437,3 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
args
}
mod analyze;
mod block;
pub mod constant;
pub mod coverageinfo;
pub mod debuginfo;
mod intrinsic;
pub mod operand;
pub mod place;
mod rvalue;
mod statement;

View File

@ -20,7 +20,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
LocalRef::PendingOperand => {
let operand = self.codegen_rvalue_operand(bx, rvalue);
self.locals[index] = LocalRef::Operand(operand);
self.overwrite_local(index, LocalRef::Operand(operand));
self.debug_introduce_local(bx, index);
}
LocalRef::Operand(op) => {

View File

@ -44,6 +44,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
// #[target_feature].
("thumb-mode", Some(sym::arm_target_feature)),
("thumb2", Some(sym::arm_target_feature)),
("trustzone", Some(sym::arm_target_feature)),
("v5te", Some(sym::arm_target_feature)),
("v6", Some(sym::arm_target_feature)),
("v6k", Some(sym::arm_target_feature)),
@ -53,6 +54,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("vfp2", Some(sym::arm_target_feature)),
("vfp3", Some(sym::arm_target_feature)),
("vfp4", Some(sym::arm_target_feature)),
("virtualization", Some(sym::arm_target_feature)),
// tidy-alphabetical-end
];

View File

@ -14,7 +14,7 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_span::source_map::Span;
use rustc_target::abi::{self, Abi};
use super::{CompileTimeEvalContext, CompileTimeInterpreter};
use super::{CanAccessStatics, CompileTimeEvalContext, CompileTimeInterpreter};
use crate::errors;
use crate::interpret::eval_nullary_intrinsic;
use crate::interpret::{
@ -93,7 +93,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
tcx: TyCtxt<'tcx>,
root_span: Span,
param_env: ty::ParamEnv<'tcx>,
can_access_statics: bool,
can_access_statics: CanAccessStatics,
) -> CompileTimeEvalContext<'mir, 'tcx> {
debug!("mk_eval_cx: {:?}", param_env);
InterpCx::new(
@ -207,7 +207,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
tcx,
tcx.def_span(key.value.instance.def_id()),
key.param_env,
/*can_access_statics:*/ is_static,
CanAccessStatics::from(is_static),
);
let mplace = ecx.raw_const_to_mplace(constant).expect(
@ -309,7 +309,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
// Statics (and promoteds inside statics) may access other statics, because unlike consts
// they do not have to behave "as if" they were evaluated at runtime.
CompileTimeInterpreter::new(
/*can_access_statics:*/ is_static,
CanAccessStatics::from(is_static),
if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
CheckAlignment::Error
} else {

View File

@ -57,7 +57,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
/// * Interning makes everything outside of statics immutable.
/// * Pointers to allocations inside of statics can never leak outside, to a non-static global.
/// This boolean here controls the second part.
pub(super) can_access_statics: bool,
pub(super) can_access_statics: CanAccessStatics,
/// Whether to check alignment during evaluation.
pub(super) check_alignment: CheckAlignment,
@ -83,8 +83,23 @@ impl CheckAlignment {
}
}
#[derive(Copy, Clone, PartialEq)]
pub(crate) enum CanAccessStatics {
No,
Yes,
}
impl From<bool> for CanAccessStatics {
fn from(value: bool) -> Self {
if value { Self::Yes } else { Self::No }
}
}
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
pub(crate) fn new(can_access_statics: bool, check_alignment: CheckAlignment) -> Self {
pub(crate) fn new(
can_access_statics: CanAccessStatics,
check_alignment: CheckAlignment,
) -> Self {
CompileTimeInterpreter {
num_evaluated_steps: 0,
stack: Vec::new(),
@ -699,7 +714,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
}
} else {
// Read access. These are usually allowed, with some exceptions.
if machine.can_access_statics {
if machine.can_access_statics == CanAccessStatics::Yes {
// Machine configuration allows us read from anything (e.g., `static` initializer).
Ok(())
} else if static_def_id.is_some() {

View File

@ -26,7 +26,7 @@ pub(crate) fn const_caller_location(
(file, line, col): (Symbol, u32, u32),
) -> ConstValue<'_> {
trace!("const_caller_location: {}:{}:{}", file, line, col);
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false);
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), CanAccessStatics::No);
let loc_place = ecx.alloc_caller_location(file, line, col);
if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
@ -55,10 +55,12 @@ pub(crate) fn eval_to_valtree<'tcx>(
// FIXME Need to provide a span to `eval_to_valtree`
let ecx = mk_eval_cx(
tcx, DUMMY_SP, param_env,
tcx,
DUMMY_SP,
param_env,
// It is absolutely crucial for soundness that
// we do not read from static items or other mutable memory.
false,
CanAccessStatics::No,
);
let place = ecx.raw_const_to_mplace(const_alloc).unwrap();
debug!(?place);
@ -91,7 +93,7 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
val: mir::ConstantKind<'tcx>,
) -> InterpResult<'tcx, mir::DestructuredConstant<'tcx>> {
trace!("destructure_mir_constant: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
let op = ecx.eval_mir_constant(&val, None, None)?;
// We go to `usize` as we cannot allocate anything bigger anyway.

View File

@ -1,6 +1,7 @@
use super::eval_queries::{mk_eval_cx, op_to_const};
use super::machine::CompileTimeEvalContext;
use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
use crate::const_eval::CanAccessStatics;
use crate::interpret::{
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
MemoryKind, PlaceTy, Scalar,
@ -263,7 +264,11 @@ pub fn valtree_to_const_value<'tcx>(
// FIXME Does this need an example?
let (param_env, ty) = param_env_ty.into_parts();
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
let mut ecx: crate::interpret::InterpCx<
'_,
'_,
crate::const_eval::CompileTimeInterpreter<'_, '_>,
> = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
match ty.kind() {
ty::FnDef(..) => {

View File

@ -612,30 +612,28 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
fn visit_projection_elem(
&mut self,
place_local: Local,
proj_base: &[PlaceElem<'tcx>],
place_ref: PlaceRef<'tcx>,
elem: PlaceElem<'tcx>,
context: PlaceContext,
location: Location,
) {
trace!(
"visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \
"visit_projection_elem: place_ref={:?} elem={:?} \
context={:?} location={:?}",
place_local,
proj_base,
place_ref,
elem,
context,
location,
);
self.super_projection_elem(place_local, proj_base, elem, context, location);
self.super_projection_elem(place_ref, elem, context, location);
match elem {
ProjectionElem::Deref => {
let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
let base_ty = place_ref.ty(self.body, self.tcx).ty;
if base_ty.is_unsafe_ptr() {
if proj_base.is_empty() {
let decl = &self.body.local_decls[place_local];
if place_ref.projection.is_empty() {
let decl = &self.body.local_decls[place_ref.local];
if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
let span = decl.source_info.span;
self.check_static(def_id, span);

View File

@ -318,8 +318,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
fn visit_projection_elem(
&mut self,
local: Local,
proj_base: &[PlaceElem<'tcx>],
place_ref: PlaceRef<'tcx>,
elem: PlaceElem<'tcx>,
context: PlaceContext,
location: Location,
@ -334,7 +333,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
ProjectionElem::Deref
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) =>
{
let base_ty = Place::ty_from(local, proj_base, &self.body.local_decls, self.tcx).ty;
let base_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty;
if base_ty.is_box() {
self.fail(
@ -344,8 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
ProjectionElem::Field(f, ty) => {
let parent = Place { local, projection: self.tcx.mk_place_elems(proj_base) };
let parent_ty = parent.ty(&self.body.local_decls, self.tcx);
let parent_ty = place_ref.ty(&self.body.local_decls, self.tcx);
let fail_out_of_bounds = |this: &Self, location| {
this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty));
};
@ -355,7 +353,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
location,
format!(
"Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
parent, f, ty, f_ty
place_ref, f, ty, f_ty
)
)
}
@ -434,7 +432,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
_ => {}
}
self.super_projection_elem(local, proj_base, elem, context, location);
self.super_projection_elem(place_ref, elem, context, location);
}
fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {

View File

@ -2,7 +2,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, Val
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
use crate::const_eval::{CanAccessStatics, CheckAlignment, CompileTimeInterpreter};
use crate::interpret::{InterpCx, MemoryKind, OpTy};
/// Determines if this type permits "raw" initialization by just transmuting some memory into an
@ -44,8 +44,7 @@ fn might_permit_raw_init_strict<'tcx>(
tcx: TyCtxt<'tcx>,
kind: ValidityRequirement,
) -> Result<bool, LayoutError<'tcx>> {
let machine =
CompileTimeInterpreter::new(/*can_access_statics:*/ false, CheckAlignment::Error);
let machine = CompileTimeInterpreter::new(CanAccessStatics::No, CheckAlignment::Error);
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);

View File

@ -3,6 +3,8 @@ use std::fmt;
use std::fs;
use std::io;
use rustc_session::EarlyErrorHandler;
fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
if let Some(path) = arg.strip_prefix('@') {
let file = match fs::read_to_string(path) {
@ -21,15 +23,12 @@ fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
/// **Note:** This function doesn't interpret argument 0 in any special way.
/// If this function is intended to be used with command line arguments,
/// `argv[0]` must be removed prior to calling it manually.
pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
pub fn arg_expand_all(handler: &EarlyErrorHandler, at_args: &[String]) -> Vec<String> {
let mut args = Vec::new();
for arg in at_args {
match arg_expand(arg.clone()) {
Ok(arg) => args.extend(arg),
Err(err) => rustc_session::early_error(
rustc_session::config::ErrorOutputType::default(),
format!("Failed to load argument file: {err}"),
),
Err(err) => handler.early_error(format!("Failed to load argument file: {err}")),
}
}
args

View File

@ -40,8 +40,7 @@ use rustc_session::config::{
use rustc_session::cstore::MetadataLoader;
use rustc_session::getopts::{self, Matches};
use rustc_session::lint::{Lint, LintId};
use rustc_session::{config, Session};
use rustc_session::{early_error, early_error_no_abort, early_warn};
use rustc_session::{config, EarlyErrorHandler, Session};
use rustc_span::source_map::{FileLoader, FileName};
use rustc_span::symbol::sym;
use rustc_target::json::ToJson;
@ -174,6 +173,7 @@ pub trait Callbacks {
/// continue the compilation afterwards (defaults to `Compilation::Continue`)
fn after_analysis<'tcx>(
&mut self,
_handler: &EarlyErrorHandler,
_compiler: &interface::Compiler,
_queries: &'tcx Queries<'tcx>,
) -> Compilation {
@ -260,6 +260,8 @@ fn run_compiler(
Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
>,
) -> interface::Result<()> {
let mut early_error_handler = EarlyErrorHandler::new(ErrorOutputType::default());
// Throw away the first argument, the name of the binary.
// In case of at_args being empty, as might be the case by
// passing empty argument array to execve under some platforms,
@ -270,22 +272,22 @@ fn run_compiler(
// the compiler with @empty_file as argv[0] and no more arguments.
let at_args = at_args.get(1..).unwrap_or_default();
let args = args::arg_expand_all(at_args);
let args = args::arg_expand_all(&early_error_handler, at_args);
let Some(matches) = handle_options(&args) else { return Ok(()) };
let Some(matches) = handle_options(&early_error_handler, &args) else { return Ok(()) };
let sopts = config::build_session_options(&matches);
let sopts = config::build_session_options(&mut early_error_handler, &matches);
// Set parallel mode before thread pool creation, which will create `Lock`s.
interface::set_thread_safe_mode(&sopts.unstable_opts);
if let Some(ref code) = matches.opt_str("explain") {
handle_explain(diagnostics_registry(), code, sopts.error_format);
handle_explain(&early_error_handler, diagnostics_registry(), code);
return Ok(());
}
let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
let check_cfg = interface::parse_check_cfg(matches.opt_strs("check-cfg"));
let cfg = interface::parse_cfgspecs(&early_error_handler, matches.opt_strs("cfg"));
let check_cfg = interface::parse_check_cfg(&early_error_handler, matches.opt_strs("check-cfg"));
let (odir, ofile) = make_output(&matches);
let mut config = interface::Config {
opts: sopts,
@ -304,7 +306,7 @@ fn run_compiler(
registry: diagnostics_registry(),
};
match make_input(config.opts.error_format, &matches.free) {
match make_input(&early_error_handler, &matches.free) {
Err(reported) => return Err(reported),
Ok(Some(input)) => {
config.input = input;
@ -314,8 +316,13 @@ fn run_compiler(
Ok(None) => match matches.free.len() {
0 => {
callbacks.config(&mut config);
early_error_handler.abort_if_errors();
interface::run_compiler(config, |compiler| {
let sopts = &compiler.session().opts;
let handler = EarlyErrorHandler::new(sopts.error_format);
if sopts.describe_lints {
let mut lint_store =
rustc_lint::new_lint_store(compiler.session().enable_internal_lints());
@ -329,31 +336,38 @@ fn run_compiler(
describe_lints(compiler.session(), &lint_store, registered_lints);
return;
}
let should_stop =
print_crate_info(&**compiler.codegen_backend(), compiler.session(), false);
let should_stop = print_crate_info(
&handler,
&**compiler.codegen_backend(),
compiler.session(),
false,
);
if should_stop == Compilation::Stop {
return;
}
early_error(sopts.error_format, "no input filename given")
handler.early_error("no input filename given")
});
return Ok(());
}
1 => panic!("make_input should have provided valid inputs"),
_ => early_error(
config.opts.error_format,
format!(
_ => early_error_handler.early_error(format!(
"multiple input filenames provided (first two filenames are `{}` and `{}`)",
matches.free[0], matches.free[1],
),
),
)),
},
};
early_error_handler.abort_if_errors();
interface::run_compiler(config, |compiler| {
let sess = compiler.session();
let should_stop = print_crate_info(&**compiler.codegen_backend(), sess, true)
.and_then(|| list_metadata(sess, &*compiler.codegen_backend().metadata_loader()))
let handler = EarlyErrorHandler::new(sess.opts.error_format);
let should_stop = print_crate_info(&handler, &**compiler.codegen_backend(), sess, true)
.and_then(|| {
list_metadata(&handler, sess, &*compiler.codegen_backend().metadata_loader())
})
.and_then(|| try_process_rlink(sess, compiler));
if should_stop == Compilation::Stop {
@ -421,7 +435,7 @@ fn run_compiler(
queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?;
if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
if callbacks.after_analysis(&handler, compiler, queries) == Compilation::Stop {
return early_exit();
}
@ -475,7 +489,7 @@ fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<OutFileNa
// Extract input (string or file and optional path) from matches.
fn make_input(
error_format: ErrorOutputType,
handler: &EarlyErrorHandler,
free_matches: &[String],
) -> Result<Option<Input>, ErrorGuaranteed> {
if free_matches.len() == 1 {
@ -485,8 +499,7 @@ fn make_input(
if io::stdin().read_to_string(&mut src).is_err() {
// Immediately stop compilation if there was an issue reading
// the input (for example if the input stream is not UTF-8).
let reported = early_error_no_abort(
error_format,
let reported = handler.early_error_no_abort(
"couldn't read from stdin, as it did not contain valid UTF-8",
);
return Err(reported);
@ -527,7 +540,7 @@ impl Compilation {
}
}
fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
fn handle_explain(handler: &EarlyErrorHandler, registry: Registry, code: &str) {
let upper_cased_code = code.to_ascii_uppercase();
let normalised =
if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") };
@ -557,7 +570,7 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
}
}
Err(InvalidErrorCode) => {
early_error(output, format!("{code} is not a valid error code"));
handler.early_error(format!("{code} is not a valid error code"));
}
}
}
@ -636,7 +649,11 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp
}
}
pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Compilation {
pub fn list_metadata(
handler: &EarlyErrorHandler,
sess: &Session,
metadata_loader: &dyn MetadataLoader,
) -> Compilation {
if sess.opts.unstable_opts.ls {
match sess.io.input {
Input::File(ref ifile) => {
@ -646,7 +663,7 @@ pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Co
safe_println!("{}", String::from_utf8(v).unwrap());
}
Input::Str { .. } => {
early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
handler.early_error("cannot list metadata for stdin");
}
}
return Compilation::Stop;
@ -656,6 +673,7 @@ pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Co
}
fn print_crate_info(
handler: &EarlyErrorHandler,
codegen_backend: &dyn CodegenBackend,
sess: &Session,
parse_attrs: bool,
@ -787,10 +805,8 @@ fn print_crate_info(
.expect("unknown Apple target OS")
)
} else {
early_error(
ErrorOutputType::default(),
"only Apple targets currently support deployment version info",
)
handler
.early_error("only Apple targets currently support deployment version info")
}
}
}
@ -801,11 +817,12 @@ fn print_crate_info(
/// Prints version information
///
/// NOTE: this is a macro to support drivers built at a different time than the main `rustc_driver` crate.
pub macro version($binary: literal, $matches: expr) {
pub macro version($handler: expr, $binary: literal, $matches: expr) {
fn unw(x: Option<&str>) -> &str {
x.unwrap_or("unknown")
}
$crate::version_at_macro_invocation(
$handler,
$binary,
$matches,
unw(option_env!("CFG_VERSION")),
@ -817,6 +834,7 @@ pub macro version($binary: literal, $matches: expr) {
#[doc(hidden)] // use the macro instead
pub fn version_at_macro_invocation(
handler: &EarlyErrorHandler,
binary: &str,
matches: &getopts::Matches,
version: &str,
@ -837,7 +855,7 @@ pub fn version_at_macro_invocation(
let debug_flags = matches.opt_strs("Z");
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
get_codegen_backend(&None, backend_name).print_version();
get_codegen_backend(handler, &None, backend_name).print_version();
}
}
@ -1014,7 +1032,7 @@ Available lint options:
/// Show help for flag categories shared between rustdoc and rustc.
///
/// Returns whether a help option was printed.
pub fn describe_flag_categories(matches: &Matches) -> bool {
pub fn describe_flag_categories(handler: &EarlyErrorHandler, matches: &Matches) -> bool {
// Handle the special case of -Wall.
let wall = matches.opt_strs("W");
if wall.iter().any(|x| *x == "all") {
@ -1036,15 +1054,12 @@ pub fn describe_flag_categories(matches: &Matches) -> bool {
}
if cg_flags.iter().any(|x| *x == "no-stack-check") {
early_warn(
ErrorOutputType::default(),
"the --no-stack-check flag is deprecated and does nothing",
);
handler.early_warn("the --no-stack-check flag is deprecated and does nothing");
}
if cg_flags.iter().any(|x| *x == "passes=list") {
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
get_codegen_backend(&None, backend_name).print_passes();
get_codegen_backend(handler, &None, backend_name).print_passes();
return true;
}
@ -1101,7 +1116,7 @@ fn print_flag_list<T>(
///
/// So with all that in mind, the comments below have some more detail about the
/// contortions done here to get things to work out correctly.
pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
pub fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<getopts::Matches> {
if args.is_empty() {
// user did not write `-v` nor `-Z unstable-options`, so do not
// include that extra information.
@ -1127,7 +1142,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
.map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
_ => None,
};
early_error(ErrorOutputType::default(), msg.unwrap_or_else(|| e.to_string()));
handler.early_error(msg.unwrap_or_else(|| e.to_string()));
});
// For all options we just parsed, we check a few aspects:
@ -1141,7 +1156,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
// we're good to go.
// * Otherwise, if we're an unstable option then we generate an error
// (unstable option being used on stable)
nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
nightly_options::check_nightly_options(handler, &matches, &config::rustc_optgroups());
if matches.opt_present("h") || matches.opt_present("help") {
// Only show unstable options in --help if we accept unstable options.
@ -1151,12 +1166,12 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
return None;
}
if describe_flag_categories(&matches) {
if describe_flag_categories(handler, &matches) {
return None;
}
if matches.opt_present("version") {
version!("rustc", &matches);
version!(handler, "rustc", &matches);
return None;
}
@ -1276,7 +1291,8 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
if let Some(msg) = info.payload().downcast_ref::<String>() {
if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") {
// the error code is already going to be reported when the panic unwinds up the stack
let _ = early_error_no_abort(ErrorOutputType::default(), msg.clone());
let handler = EarlyErrorHandler::new(ErrorOutputType::default());
let _ = handler.early_error_no_abort(msg.clone());
return;
}
};
@ -1359,16 +1375,16 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info:
/// This allows tools to enable rust logging without having to magically match rustc's
/// tracing crate version.
pub fn init_rustc_env_logger() {
init_env_logger("RUSTC_LOG");
pub fn init_rustc_env_logger(handler: &EarlyErrorHandler) {
init_env_logger(handler, "RUSTC_LOG");
}
/// This allows tools to enable rust logging without having to magically match rustc's
/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
/// other than `RUSTC_LOG`.
pub fn init_env_logger(env: &str) {
pub fn init_env_logger(handler: &EarlyErrorHandler, env: &str) {
if let Err(error) = rustc_log::init_env_logger(env) {
early_error(ErrorOutputType::default(), error.to_string());
handler.early_error(error.to_string());
}
}
@ -1424,7 +1440,10 @@ mod signal_handler {
pub fn main() -> ! {
let start_time = Instant::now();
let start_rss = get_resident_set_size();
init_rustc_env_logger();
let handler = EarlyErrorHandler::new(ErrorOutputType::default());
init_rustc_env_logger(&handler);
signal_handler::install();
let mut callbacks = TimePassesCallbacks::default();
install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
@ -1433,10 +1452,7 @@ pub fn main() -> ! {
.enumerate()
.map(|(i, arg)| {
arg.into_string().unwrap_or_else(|arg| {
early_error(
ErrorOutputType::default(),
format!("argument {i} is not valid Unicode: {arg:?}"),
)
handler.early_error(format!("argument {i} is not valid Unicode: {arg:?}"))
})
})
.collect::<Vec<_>>();

View File

@ -445,7 +445,7 @@ impl<'a> StripUnconfigured<'a> {
/// If attributes are not allowed on expressions, emit an error for `attr`
#[instrument(level = "trace", skip(self))]
pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
if !self.features.map_or(true, |features| features.stmt_expr_attributes) {
if self.features.is_some_and(|features| !features.stmt_expr_attributes) {
let mut err = feature_err(
&self.sess.parse_sess,
sym::stmt_expr_attributes,

View File

@ -179,7 +179,8 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
let mut previous_defns = HashMap::new();
let mut message_refs = Vec::new();
for entry in resource.entries() {
if let Entry::Message(Message { id: Identifier { name }, attributes, value, .. }) = entry {
if let Entry::Message(msg) = entry {
let Message { id: Identifier { name }, attributes, value, .. } = msg;
let _ = previous_defns.entry(name.to_string()).or_insert(resource_span);
if name.contains('-') {
Diagnostic::spanned(
@ -229,9 +230,10 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
continue;
}
let msg = format!("Constant referring to Fluent message `{name}` from `{crate_name}`");
let docstr =
format!("Constant referring to Fluent message `{name}` from `{crate_name}`");
constants.extend(quote! {
#[doc = #msg]
#[doc = #docstr]
pub const #snake_name: crate::DiagnosticMessage =
crate::DiagnosticMessage::FluentIdentifier(
std::borrow::Cow::Borrowed(#name),
@ -269,6 +271,15 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
);
});
}
// Record variables referenced by these messages so we can produce
// tests in the derive diagnostics to validate them.
let ident = quote::format_ident!("{snake_name}_refs");
let vrefs = variable_references(msg);
constants.extend(quote! {
#[cfg(test)]
pub const #ident: &[&str] = &[#(#vrefs),*];
})
}
}
@ -334,3 +345,28 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
}
.into()
}
fn variable_references<'a>(msg: &Message<&'a str>) -> Vec<&'a str> {
let mut refs = vec![];
if let Some(Pattern { elements }) = &msg.value {
for elt in elements {
if let PatternElement::Placeable {
expression: Expression::Inline(InlineExpression::VariableReference { id }),
} = elt
{
refs.push(id.name);
}
}
}
for attr in &msg.attributes {
for elt in &attr.value.elements {
if let PatternElement::Placeable {
expression: Expression::Inline(InlineExpression::VariableReference { id }),
} = elt
{
refs.push(id.name);
}
}
}
refs
}

View File

@ -1719,6 +1719,7 @@ impl Expr<'_> {
ExprKind::Break(..) => ExprPrecedence::Break,
ExprKind::Continue(..) => ExprPrecedence::Continue,
ExprKind::Ret(..) => ExprPrecedence::Ret,
ExprKind::Become(..) => ExprPrecedence::Become,
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
ExprKind::OffsetOf(..) => ExprPrecedence::OffsetOf,
ExprKind::Struct(..) => ExprPrecedence::Struct,
@ -1776,6 +1777,7 @@ impl Expr<'_> {
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
| ExprKind::Become(..)
| ExprKind::Let(..)
| ExprKind::Loop(..)
| ExprKind::Assign(..)
@ -1866,6 +1868,7 @@ impl Expr<'_> {
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
| ExprKind::Become(..)
| ExprKind::Let(..)
| ExprKind::Loop(..)
| ExprKind::Assign(..)
@ -2025,6 +2028,8 @@ pub enum ExprKind<'hir> {
Continue(Destination),
/// A `return`, with an optional value to be returned.
Ret(Option<&'hir Expr<'hir>>),
/// A `become`, with the value to be returned.
Become(&'hir Expr<'hir>),
/// Inline assembly (from `asm!`), with its outputs and inputs.
InlineAsm(&'hir InlineAsm<'hir>),

View File

@ -791,6 +791,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
ExprKind::Ret(ref optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression);
}
ExprKind::Become(ref expr) => visitor.visit_expr(expr),
ExprKind::InlineAsm(ref asm) => {
visitor.visit_inline_asm(asm, expression.hir_id);
}

View File

@ -137,7 +137,7 @@ hir_analysis_missing_trait_item_suggestion = implement the missing item: `{$snip
hir_analysis_missing_trait_item_unstable = not all trait items implemented, missing: `{$missing_item_name}`
.note = default implementation of `{$missing_item_name}` is unstable
.some_note = use of unstable library feature '{$feature}': {$r}
.some_note = use of unstable library feature '{$feature}': {$reason}
.none_note = use of unstable library feature '{$feature}'
hir_analysis_missing_type_params =

View File

@ -945,11 +945,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut trait_bounds = vec![];
let mut projection_bounds = vec![];
for (clause, span) in bounds.clauses() {
let pred: ty::Predicate<'tcx> = clause.as_predicate();
for (pred, span) in bounds.clauses() {
let bound_pred = pred.kind();
match bound_pred.skip_binder() {
ty::PredicateKind::Clause(clause) => match clause {
ty::ClauseKind::Trait(trait_pred) => {
assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
trait_bounds.push((
@ -967,18 +965,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ty::ClauseKind::RegionOutlives(_)
| ty::ClauseKind::ConstArgHasType(..)
| ty::ClauseKind::WellFormed(_)
| ty::ClauseKind::ConstEvaluatable(_) => {
| ty::ClauseKind::ConstEvaluatable(_)
| ty::ClauseKind::TypeWellFormedFromEnv(_) => {
bug!()
}
},
ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::ClosureKind(_, _, _)
| ty::PredicateKind::Subtype(_)
| ty::PredicateKind::Coerce(_)
| ty::PredicateKind::ConstEquate(_, _)
| ty::PredicateKind::TypeWellFormedFromEnv(_)
| ty::PredicateKind::Ambiguous => bug!(),
}
}
@ -1425,9 +1415,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|| {
traits::transitive_bounds_that_define_assoc_item(
tcx,
predicates.iter().filter_map(|(p, _)| {
Some(p.to_opt_poly_trait_pred()?.map_bound(|t| t.trait_ref))
}),
predicates
.iter()
.filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))),
assoc_name,
)
},

View File

@ -220,7 +220,7 @@ fn compare_method_predicate_entailment<'tcx>(
// the new hybrid bounds we computed.
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
let param_env = ty::ParamEnv::new(
tcx.mk_predicates(&hybrid_preds.predicates),
tcx.mk_clauses(&hybrid_preds.predicates),
Reveal::UserFacing,
hir::Constness::NotConst,
);
@ -1835,7 +1835,7 @@ fn compare_type_predicate_entailment<'tcx>(
let impl_ty_span = tcx.def_span(impl_ty_def_id);
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id);
let param_env = ty::ParamEnv::new(
tcx.mk_predicates(&hybrid_preds.predicates),
tcx.mk_clauses(&hybrid_preds.predicates),
Reveal::UserFacing,
hir::Constness::NotConst,
);
@ -2011,7 +2011,7 @@ pub(super) fn check_type_bounds<'tcx>(
.to_predicate(tcx),
),
};
ty::ParamEnv::new(tcx.mk_predicates(&predicates), Reveal::UserFacing, param_env.constness())
ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing, param_env.constness())
};
debug!(?normalize_param_env);

View File

@ -296,7 +296,7 @@ fn default_body_is_unstable(
/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
fn bounds_from_generic_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>,
predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
) -> (String, String) {
let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
let mut projections = vec![];
@ -304,7 +304,7 @@ fn bounds_from_generic_predicates<'tcx>(
debug!("predicate {:?}", predicate);
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
ty::ClauseKind::Trait(trait_predicate) => {
let entry = types.entry(trait_predicate.self_ty()).or_default();
let def_id = trait_predicate.def_id();
if Some(def_id) != tcx.lang_items().sized_trait() {
@ -313,7 +313,7 @@ fn bounds_from_generic_predicates<'tcx>(
entry.push(trait_predicate.def_id());
}
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection_pred)) => {
ty::ClauseKind::Projection(projection_pred) => {
projections.push(bound_predicate.rebind(projection_pred));
}
_ => {}
@ -362,7 +362,7 @@ fn fn_sig_suggestion<'tcx>(
tcx: TyCtxt<'tcx>,
sig: ty::FnSig<'tcx>,
ident: Ident,
predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>,
predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
assoc: ty::AssocItem,
) -> String {
let args = sig

View File

@ -15,7 +15,7 @@ use rustc_middle::mir::ConstraintCategory;
use rustc_middle::query::Providers;
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
self, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt, TypeVisitor,
};
use rustc_middle::ty::{GenericArgKind, InternalSubsts};
@ -322,7 +322,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
// Gather the bounds with which all other items inside of this trait constrain the GAT.
// This is calculated by taking the intersection of the bounds that each item
// constrains the GAT with individually.
let mut new_required_bounds: Option<FxHashSet<ty::Predicate<'_>>> = None;
let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None;
for item in associated_items {
let item_def_id = item.id.owner_id;
// Skip our own GAT, since it does not constrain itself at all.
@ -419,9 +419,17 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
let mut unsatisfied_bounds: Vec<_> = required_bounds
.into_iter()
.filter(|clause| match clause.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
ty::OutlivesPredicate(a, b),
)) => !region_known_to_outlive(
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
!region_known_to_outlive(
tcx,
gat_def_id.def_id,
param_env,
&FxIndexSet::default(),
a,
b,
)
}
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => !ty_known_to_outlive(
tcx,
gat_def_id.def_id,
param_env,
@ -429,18 +437,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
a,
b,
),
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
a,
b,
))) => !ty_known_to_outlive(
tcx,
gat_def_id.def_id,
param_env,
&FxIndexSet::default(),
a,
b,
),
_ => bug!("Unexpected PredicateKind"),
_ => bug!("Unexpected ClauseKind"),
})
.map(|clause| clause.to_string())
.collect();
@ -488,7 +485,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
fn augment_param_env<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
new_predicates: Option<&FxHashSet<ty::Predicate<'tcx>>>,
new_predicates: Option<&FxHashSet<ty::Clause<'tcx>>>,
) -> ty::ParamEnv<'tcx> {
let Some(new_predicates) = new_predicates else {
return param_env;
@ -498,7 +495,7 @@ fn augment_param_env<'tcx>(
return param_env;
}
let bounds = tcx.mk_predicates_from_iter(
let bounds = tcx.mk_clauses_from_iter(
param_env.caller_bounds().iter().chain(new_predicates.iter().cloned()),
);
// FIXME(compiler-errors): Perhaps there is a case where we need to normalize this
@ -524,7 +521,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
wf_tys: &FxIndexSet<Ty<'tcx>>,
gat_def_id: LocalDefId,
gat_generics: &'tcx ty::Generics,
) -> Option<FxHashSet<ty::Predicate<'tcx>>> {
) -> Option<FxHashSet<ty::Clause<'tcx>>> {
// The bounds we that we would require from `to_check`
let mut bounds = FxHashSet::default();
@ -573,11 +570,10 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
);
// The predicate we expect to see. (In our example,
// `Self: 'me`.)
let clause = ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
ty::OutlivesPredicate(ty_param, region_param),
));
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
bounds.insert(clause);
bounds.insert(
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_param, region_param))
.to_predicate(tcx),
);
}
}
@ -622,11 +618,13 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
},
);
// The predicate we expect to see.
let clause = ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
ty::OutlivesPredicate(region_a_param, region_b_param),
));
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
bounds.insert(clause);
bounds.insert(
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
region_a_param,
region_b_param,
))
.to_predicate(tcx),
);
}
}
}
@ -1406,7 +1404,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
infcx,
wfcx.param_env.without_const(),
wfcx.body_def_id,
p,
p.as_predicate(),
sp,
)
});
@ -1549,7 +1547,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
{
let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| {
match re.kind() {
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) => re,
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) | ty::ReStatic => re,
r => bug!("unexpected region: {r:?}"),
}
});
@ -1875,9 +1873,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
// We lower empty bounds like `Vec<dyn Copy>:` as
// `WellFormed(Vec<dyn Copy>)`, which will later get checked by
// regular WF checking
if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) =
pred.kind().skip_binder()
{
if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() {
continue;
}
// Match the existing behavior.

View File

@ -140,7 +140,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
impl1_def_id: DefId,
impl2_def_id: DefId,
) {
traits::overlapping_impls(
let maybe_overlap = traits::overlapping_impls(
self.tcx,
impl1_def_id,
impl2_def_id,
@ -148,11 +148,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
// inherent impls without warning.
SkipLeakCheck::Yes,
overlap_mode,
)
.map_or(true, |overlap| {
);
if let Some(overlap) = maybe_overlap {
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
false
});
}
}
fn check_item(&mut self, id: hir::ItemId) {

View File

@ -38,16 +38,12 @@ fn associated_type_bounds<'tcx>(
.iter()
.copied()
.filter(|(pred, _)| match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => tr.self_ty() == item_ty,
ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => {
proj.projection_ty.self_ty() == item_ty
}
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
outlives.0 == item_ty
}
ty::ClauseKind::Trait(tr) => tr.self_ty() == item_ty,
ty::ClauseKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
ty::ClauseKind::TypeOutlives(outlives) => outlives.0 == item_ty,
_ => false,
})
.map(|(pred, span)| (pred.expect_clause(), span));
.map(|(clause, span)| (clause, span));
let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent));
debug!(

View File

@ -75,7 +75,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// We use an `IndexSet` to preserve order of insertion.
// Preserving the order of insertion is important here so as not to break UI tests.
let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default();
let ast_generics = match node {
Node::TraitItem(item) => item.generics,
@ -126,8 +126,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
predicates.extend(
icx.astconv()
.compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false))
.clauses()
.map(|(clause, span)| (clause.as_predicate(), span)),
.clauses(),
);
}
@ -176,8 +175,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
param.span,
);
trace!(?bounds);
predicates
.extend(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)));
predicates.extend(bounds.clauses());
trace!(?predicates);
}
GenericParamKind::Const { .. } => {
@ -188,11 +186,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
let ct = tcx.mk_const(param_const, ct_ty);
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
ty::ClauseKind::ConstArgHasType(ct, ct_ty),
))
.to_predicate(tcx);
predicates.insert((predicate, param.span));
predicates.insert((
ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx),
param.span,
));
index += 1;
}
@ -221,7 +218,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
} else {
let span = bound_pred.bounded_ty.span;
let predicate = ty::Binder::bind_with_vars(
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into())),
ty::ClauseKind::WellFormed(ty.into()),
bound_vars,
);
predicates.insert((predicate.to_predicate(tcx), span));
@ -236,8 +233,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
bound_vars,
OnlySelfBounds(false),
);
predicates
.extend(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)));
predicates.extend(bounds.clauses());
}
hir::WherePredicate::RegionPredicate(region_pred) => {
@ -249,11 +245,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}
_ => bug!(),
};
let pred = ty::Binder::dummy(ty::PredicateKind::Clause(
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)),
))
let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
.to_predicate(icx.tcx);
(pred, span)
}))
}
@ -318,16 +311,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
},
);
predicates.push((
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
ty::OutlivesPredicate(orig_region, dup_region),
)))
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_region, dup_region))
.to_predicate(icx.tcx),
duplicate.span,
));
predicates.push((
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
ty::OutlivesPredicate(dup_region, orig_region),
)))
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_region, orig_region))
.to_predicate(icx.tcx),
duplicate.span,
));
@ -344,10 +333,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
fn const_evaluatable_predicates_of(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
) -> FxIndexSet<(ty::Predicate<'_>, Span)> {
) -> FxIndexSet<(ty::Clause<'_>, Span)> {
struct ConstCollector<'tcx> {
tcx: TyCtxt<'tcx>,
preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
preds: FxIndexSet<(ty::Clause<'tcx>, Span)>,
}
impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
@ -355,13 +344,8 @@ fn const_evaluatable_predicates_of(
let ct = ty::Const::from_anon_const(self.tcx, c.def_id);
if let ty::ConstKind::Unevaluated(_) = ct.kind() {
let span = self.tcx.def_span(c.def_id);
self.preds.insert((
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(
ct,
)))
.to_predicate(self.tcx),
span,
));
self.preds
.insert((ty::ClauseKind::ConstEvaluatable(ct).to_predicate(self.tcx), span));
}
}
@ -449,15 +433,9 @@ pub(super) fn explicit_predicates_of<'tcx>(
.iter()
.copied()
.filter(|(pred, _)| match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => {
!is_assoc_item_ty(tr.self_ty())
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => {
!is_assoc_item_ty(proj.projection_ty.self_ty())
}
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
!is_assoc_item_ty(outlives.0)
}
ty::ClauseKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
ty::ClauseKind::Projection(proj) => !is_assoc_item_ty(proj.projection_ty.self_ty()),
ty::ClauseKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
_ => true,
})
.collect();
@ -498,9 +476,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
.predicates
.into_iter()
.filter(|(pred, _)| {
if let ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) =
pred.kind().skip_binder()
{
if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() {
match ct.kind() {
ty::ConstKind::Param(param_const) => {
let defaulted_param_idx = tcx
@ -665,12 +641,8 @@ pub(super) fn implied_predicates_with_filter(
};
// Combine the two lists to form the complete set of superbounds:
let implied_bounds = &*tcx.arena.alloc_from_iter(
superbounds
.clauses()
.map(|(clause, span)| (clause.as_predicate(), span))
.chain(where_bounds_that_match),
);
let implied_bounds =
&*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match));
debug!(?implied_bounds);
// Now require that immediate supertraits are converted, which will, in
@ -679,7 +651,7 @@ pub(super) fn implied_predicates_with_filter(
if matches!(filter, PredicateFilter::SelfOnly) {
for &(pred, span) in implied_bounds {
debug!("superbound: {:?}", pred);
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(bound)) = pred.kind().skip_binder()
if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder()
&& bound.polarity == ty::ImplPolarity::Positive
{
tcx.at(span).super_predicates_of(bound.def_id());
@ -776,9 +748,7 @@ pub(super) fn type_param_predicates(
)
.into_iter()
.filter(|(predicate, _)| match predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
data.self_ty().is_param(index)
}
ty::ClauseKind::Trait(data) => data.self_ty().is_param(index),
_ => false,
}),
);
@ -800,7 +770,7 @@ impl<'tcx> ItemCtxt<'tcx> {
ty: Ty<'tcx>,
only_self_bounds: OnlySelfBounds,
assoc_name: Option<Ident>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
) -> Vec<(ty::Clause<'tcx>, Span)> {
let mut bounds = Bounds::default();
for predicate in ast_generics.predicates {
@ -829,7 +799,7 @@ impl<'tcx> ItemCtxt<'tcx> {
);
}
bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)).collect()
bounds.clauses().collect()
}
#[instrument(level = "trace", skip(self))]

View File

@ -1761,7 +1761,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
ty::ClauseKind::Trait(data) => {
// The order here needs to match what we would get from `subst_supertrait`
let pred_bound_vars = bound_predicate.bound_vars();
let mut all_bound_vars = bound_vars.clone();

View File

@ -151,7 +151,7 @@ pub fn identify_constrained_generic_params<'tcx>(
/// think of any.
pub fn setup_constraining_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
predicates: &mut [(ty::Predicate<'tcx>, Span)],
predicates: &mut [(ty::Clause<'tcx>, Span)],
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
input_parameters: &mut FxHashSet<Parameter>,
) {
@ -187,9 +187,7 @@ pub fn setup_constraining_predicates<'tcx>(
for j in i..predicates.len() {
// Note that we don't have to care about binders here,
// as the impl trait ref never contains any late-bound regions.
if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection)) =
predicates[j].0.kind().skip_binder()
{
if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() {
// Special case: watch out for some kind of sneaky attempt
// to project out an associated type defined by this very
// trait.

View File

@ -235,10 +235,8 @@ fn unconstrained_parent_impl_substs<'tcx>(
// what we want here. We want only a list of constrained parameters while
// the functions in `cgp` add the constrained parameters to a list of
// unconstrained parameters.
for (predicate, _) in impl_generic_predicates.predicates.iter() {
if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =
predicate.kind().skip_binder()
{
for (clause, _) in impl_generic_predicates.predicates.iter() {
if let ty::ClauseKind::Projection(proj) = clause.kind().skip_binder() {
let projection_ty = proj.projection_ty;
let projected_ty = proj.term;
@ -340,8 +338,11 @@ fn check_predicates<'tcx>(
impl2_substs: SubstsRef<'tcx>,
span: Span,
) {
let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
let impl1_predicates: Vec<_> = traits::elaborate(tcx, instantiated.into_iter()).collect();
let impl1_predicates: Vec<_> = traits::elaborate(
tcx,
tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).into_iter(),
)
.collect();
let mut impl2_predicates = if impl2_node.is_from_trait() {
// Always applicable traits have to be always applicable without any
@ -352,8 +353,8 @@ fn check_predicates<'tcx>(
tcx,
tcx.predicates_of(impl2_node.def_id())
.instantiate(tcx, impl2_substs)
.predicates
.into_iter(),
.into_iter()
.map(|(c, _s)| c.as_predicate()),
)
.collect()
};
@ -377,13 +378,13 @@ fn check_predicates<'tcx>(
let always_applicable_traits = impl1_predicates
.iter()
.copied()
.filter(|&(predicate, _)| {
.filter(|(clause, _span)| {
matches!(
trait_predicate_kind(tcx, predicate),
trait_predicate_kind(tcx, clause.as_predicate()),
Some(TraitSpecializationKind::AlwaysApplicable)
)
})
.map(|(pred, _span)| pred);
.map(|(c, _span)| c.as_predicate());
// Include the well-formed predicates of the type parameters of the impl.
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity().substs {
@ -398,9 +399,12 @@ fn check_predicates<'tcx>(
}
impl2_predicates.extend(traits::elaborate(tcx, always_applicable_traits));
for (predicate, span) in impl1_predicates {
if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(tcx, predicate, *pred2, span)) {
check_specialization_on(tcx, predicate, span)
for (clause, span) in impl1_predicates {
if !impl2_predicates
.iter()
.any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span))
{
check_specialization_on(tcx, clause.as_predicate(), span)
}
}
}
@ -550,6 +554,6 @@ fn trait_predicate_kind<'tcx>(
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
| ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => None,
}
}

View File

@ -30,40 +30,31 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
// process predicates and convert to `RequiredPredicates` entry, see below
for &(predicate, span) in predicates.predicates {
match predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(OutlivesPredicate(
ty,
reg,
))) => insert_outlives_predicate(
ty::ClauseKind::TypeOutlives(OutlivesPredicate(ty, reg)) => {
insert_outlives_predicate(
tcx,
ty.into(),
reg,
span,
&mut required_predicates,
),
)
}
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
OutlivesPredicate(reg1, reg2),
)) => insert_outlives_predicate(
ty::ClauseKind::RegionOutlives(OutlivesPredicate(reg1, reg2)) => {
insert_outlives_predicate(
tcx,
reg1.into(),
reg2,
span,
&mut required_predicates,
),
ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
| ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
| ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
)
}
ty::ClauseKind::Trait(_)
| ty::ClauseKind::Projection(_)
| ty::ClauseKind::ConstArgHasType(_, _)
| ty::ClauseKind::WellFormed(_)
| ty::ClauseKind::ConstEvaluatable(_)
| ty::ClauseKind::TypeWellFormedFromEnv(_) => {}
}
}

View File

@ -1554,6 +1554,11 @@ impl<'a> State<'a> {
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
}
}
hir::ExprKind::Become(result) => {
self.word("become");
self.word(" ");
self.print_expr_maybe_paren(result, parser::PREC_JUMP);
}
hir::ExprKind::InlineAsm(asm) => {
self.word("asm!");
self.print_inline_asm(asm);

View File

@ -78,8 +78,8 @@ hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang
hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters
hir_typeck_return_stmt_outside_of_fn_body =
return statement outside of function body
.encl_body_label = the return is part of this body...
{$statement_kind} statement outside of function body
.encl_body_label = the {$statement_kind} is part of this body...
.encl_fn_label = ...not the enclosing function body
hir_typeck_struct_expr_non_exhaustive =

View File

@ -83,6 +83,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
self.annotate_expected_due_to_let_ty(err, expr, error);
if self.is_destruct_assignment_desugaring(expr) {
return;
}
self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error);
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty);
@ -1253,6 +1257,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
// Returns whether the given expression is a destruct assignment desugaring.
// For example, `(a, b) = (1, &2);`
// Here we try to find the pattern binding of the expression,
// `default_binding_modes` is false only for destruct assignment desugaring.
pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool {
if let hir::ExprKind::Path(hir::QPath::Resolved(
_,
hir::Path { res: hir::def::Res::Local(bind_hir_id), .. },
)) = expr.kind
{
let bind = self.tcx.hir().find(*bind_hir_id);
let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id));
if let Some(hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. })) = bind &&
let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent {
return true;
}
}
return false;
}
/// This function is used to determine potential "simple" improvements or users' errors and
/// provide them useful help. For example:
///
@ -1443,6 +1467,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_,
&ty::Ref(_, checked, _),
) if self.can_sub(self.param_env, checked, expected) => {
let make_sugg = |start: Span, end: BytePos| {
// skip `(` for tuples such as `(c) = (&123)`.
// make sure we won't suggest like `(c) = 123)` which is incorrect.
let sp = sm.span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace())
.map_or(start, |s| s.shrink_to_hi());
Some((
vec![(sp.with_hi(end), String::new())],
"consider removing the borrow".to_string(),
Applicability::MachineApplicable,
true,
true,
))
};
// We have `&T`, check if what was expected was `T`. If so,
// we may want to suggest removing a `&`.
if sm.is_imported(expr.span) {
@ -1456,24 +1494,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.find(|&s| sp.contains(s))
&& sm.is_span_accessible(call_span)
{
return Some((
vec![(sp.with_hi(call_span.lo()), String::new())],
"consider removing the borrow".to_string(),
Applicability::MachineApplicable,
true,
true,
));
return make_sugg(sp, call_span.lo())
}
return None;
}
if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
return Some((
vec![(sp.with_hi(expr.span.lo()), String::new())],
"consider removing the borrow".to_string(),
Applicability::MachineApplicable,
true,
true,
));
return make_sugg(sp, expr.span.lo())
}
}
(

View File

@ -2,7 +2,10 @@
use std::borrow::Cow;
use crate::fluent_generated as fluent;
use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage};
use rustc_errors::{
AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan,
SubdiagnosticMessage,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::{
@ -31,6 +34,24 @@ pub struct ReturnStmtOutsideOfFnBody {
pub encl_body_span: Option<Span>,
#[label(hir_typeck_encl_fn_label)]
pub encl_fn_span: Option<Span>,
pub statement_kind: ReturnLikeStatementKind,
}
pub enum ReturnLikeStatementKind {
Return,
Become,
}
impl IntoDiagnosticArg for ReturnLikeStatementKind {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
let kind = match self {
Self::Return => "return",
Self::Become => "become",
}
.into();
DiagnosticArgValue::Str(kind)
}
}
#[derive(Diagnostic)]

View File

@ -5,6 +5,7 @@
use crate::cast;
use crate::coercion::CoerceMany;
use crate::coercion::DynamicCoerceMany;
use crate::errors::ReturnLikeStatementKind;
use crate::errors::TypeMismatchFruTypo;
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
use crate::errors::{
@ -324,6 +325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
ExprKind::Become(call) => self.check_expr_become(call, expr),
ExprKind::Let(let_expr) => self.check_expr_let(let_expr),
ExprKind::Loop(body, _, source, _) => {
self.check_expr_loop(body, source, expected, expr)
@ -735,47 +737,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
if self.ret_coercion.is_none() {
let mut err = ReturnStmtOutsideOfFnBody {
span: expr.span,
encl_body_span: None,
encl_fn_span: None,
};
let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id);
if let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(..),
span: encl_fn_span,
..
}))
| Some(hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
span: encl_fn_span,
..
}))
| Some(hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(..),
span: encl_fn_span,
..
})) = self.tcx.hir().find_by_def_id(encl_item_id.def_id)
{
// We are inside a function body, so reporting "return statement
// outside of function body" needs an explanation.
let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id);
// If this didn't hold, we would not have to report an error in
// the first place.
assert_ne!(encl_item_id.def_id, encl_body_owner_id);
let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
let encl_body = self.tcx.hir().body(encl_body_id);
err.encl_body_span = Some(encl_body.value.span);
err.encl_fn_span = Some(*encl_fn_span);
}
self.tcx.sess.emit_err(err);
self.emit_return_outside_of_fn_body(expr, ReturnLikeStatementKind::Return);
if let Some(e) = expr_opt {
// We still have to type-check `e` (issue #86188), but calling
@ -815,6 +777,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.types.never
}
fn check_expr_become(
&self,
call: &'tcx hir::Expr<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
match &self.ret_coercion {
Some(ret_coercion) => {
let ret_ty = ret_coercion.borrow().expected_ty();
let call_expr_ty = self.check_expr_with_hint(call, ret_ty);
// N.B. don't coerce here, as tail calls can't support most/all coercions
// FIXME(explicit_tail_calls): add a diagnostic note that `become` doesn't allow coercions
self.demand_suptype(expr.span, ret_ty, call_expr_ty);
}
None => {
self.emit_return_outside_of_fn_body(expr, ReturnLikeStatementKind::Become);
// Fallback to simply type checking `call` without hint/demanding the right types.
// Best effort to highlight more errors.
self.check_expr(call);
}
}
self.tcx.types.never
}
/// Check an expression that _is being returned_.
/// For example, this is called with `return_expr: $expr` when `return $expr`
/// is encountered.
///
/// Note that this function must only be called in function bodies.
///
/// `explicit_return` is `true` if we're checking an explicit `return expr`,
/// and `false` if we're checking a trailing expression.
pub(super) fn check_return_expr(
@ -831,11 +825,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut span = return_expr.span;
// Use the span of the trailing expression for our cause,
// not the span of the entire function
if !explicit_return {
if let ExprKind::Block(body, _) = return_expr.kind && let Some(last_expr) = body.expr {
if !explicit_return
&& let ExprKind::Block(body, _) = return_expr.kind
&& let Some(last_expr) = body.expr
{
span = last_expr.span;
}
}
ret_coercion.borrow_mut().coerce(
self,
&self.cause(span, ObligationCauseCode::ReturnValue(return_expr.hir_id)),
@ -854,6 +849,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
/// Emit an error because `return` or `become` is used outside of a function body.
///
/// `expr` is the `return` (`become`) "statement", `kind` is the kind of the statement
/// either `Return` or `Become`.
fn emit_return_outside_of_fn_body(&self, expr: &hir::Expr<'_>, kind: ReturnLikeStatementKind) {
let mut err = ReturnStmtOutsideOfFnBody {
span: expr.span,
encl_body_span: None,
encl_fn_span: None,
statement_kind: kind,
};
let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id);
if let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(..),
span: encl_fn_span,
..
}))
| Some(hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
span: encl_fn_span,
..
}))
| Some(hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(..),
span: encl_fn_span,
..
})) = self.tcx.hir().find_by_def_id(encl_item_id.def_id)
{
// We are inside a function body, so reporting "return statement
// outside of function body" needs an explanation.
let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id);
// If this didn't hold, we would not have to report an error in
// the first place.
assert_ne!(encl_item_id.def_id, encl_body_owner_id);
let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
let encl_body = self.tcx.hir().body(encl_body_id);
err.encl_body_span = Some(encl_body.value.span);
err.encl_fn_span = Some(*encl_fn_span);
}
self.tcx.sess.emit_err(err);
}
fn point_at_return_for_opaque_ty_error(
&self,
errors: &mut Vec<traits::FulfillmentError<'tcx>>,

View File

@ -326,6 +326,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
}
hir::ExprKind::Become(call) => {
self.consume_expr(call);
}
hir::ExprKind::Assign(lhs, rhs, _) => {
self.mutate_expr(lhs);
self.consume_expr(rhs);

View File

@ -683,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// inference variable.
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
| ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => None,
},
)
}

View File

@ -25,16 +25,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let generics = self.tcx.generics_of(def_id);
let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
pred.trait_ref.substs.to_vec()
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
pred.projection_ty.substs.to_vec()
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(arg, ty)) => {
ty::ClauseKind::Trait(pred) => pred.trait_ref.substs.to_vec(),
ty::ClauseKind::Projection(pred) => pred.projection_ty.substs.to_vec(),
ty::ClauseKind::ConstArgHasType(arg, ty) => {
vec![ty.into(), arg.into()]
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(e)) => vec![e.into()],
ty::ClauseKind::ConstEvaluatable(e) => vec![e.into()],
_ => return false,
};
@ -512,11 +508,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This shouldn't happen, but since this is only a diagnostic improvement, avoid breaking things.
return Err(expr);
}
let relevant_broken_predicate: ty::PredicateKind<'tcx> =
impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder();
match relevant_broken_predicate {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(broken_trait)) => {
match impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder() {
ty::ClauseKind::Trait(broken_trait) => {
// ...
self.blame_specific_part_of_expr_corresponding_to_generic_param(
broken_trait.trait_ref.self_ty().into(),

View File

@ -955,9 +955,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// - f(0, 1,)
// + f()
if only_extras_so_far
&& errors
&& !errors
.peek()
.map_or(true, |next_error| !matches!(next_error, Error::Extra(_)))
.is_some_and(|next_error| matches!(next_error, Error::Extra(_)))
{
let next = provided_arg_tys
.get(arg_idx + 1)
@ -1948,7 +1948,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// do that, so it's OK.
for (predicate, span) in instantiated
{
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = predicate.kind().skip_binder()
if let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder()
&& pred.self_ty().peel_refs() == callee_ty
&& self.tcx.is_fn_trait(pred.def_id())
{

View File

@ -226,9 +226,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
predicates: tcx.arena.alloc_from_iter(
self.param_env.caller_bounds().iter().filter_map(|predicate| {
match predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data))
if data.self_ty().is_param(index) =>
{
ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
// HACK(eddyb) should get the original `Span`.
let span = tcx.def_span(def_id);
Some((predicate, span))

View File

@ -214,6 +214,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
| ExprKind::Become(..)
| ExprKind::InlineAsm(..)
| ExprKind::OffsetOf(..)
| ExprKind::Struct(..)
@ -451,6 +452,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
}
}
ExprKind::Become(_call) => bug!("encountered a tail-call inside a generator"),
ExprKind::Call(f, args) => {
self.visit_expr(f);
for arg in args {

View File

@ -361,6 +361,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
| hir::ExprKind::AssignOp(..)
| hir::ExprKind::Closure { .. }
| hir::ExprKind::Ret(..)
| hir::ExprKind::Become(..)
| hir::ExprKind::Unary(..)
| hir::ExprKind::Yield(..)
| hir::ExprKind::MethodCall(..)

View File

@ -606,9 +606,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
traits::elaborate(self.tcx, predicates.predicates.iter().copied())
// We don't care about regions here.
.filter_map(|pred| match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))
if trait_pred.def_id() == sized_def_id =>
{
ty::ClauseKind::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => {
let span = predicates
.iter()
.find_map(|(p, span)| if p == pred { Some(span) } else { None })

View File

@ -834,7 +834,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
ty::ClauseKind::Trait(trait_predicate) => {
match *trait_predicate.trait_ref.self_ty().kind() {
ty::Param(p) if p == param_ty => {
Some(bound_predicate.rebind(trait_predicate.trait_ref))
@ -842,20 +842,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
_ => None,
}
}
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
| ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
ty::ClauseKind::RegionOutlives(_)
| ty::ClauseKind::TypeOutlives(_)
| ty::ClauseKind::Projection(_)
| ty::ClauseKind::ConstArgHasType(_, _)
| ty::ClauseKind::WellFormed(_)
| ty::ClauseKind::ConstEvaluatable(_)
| ty::ClauseKind::TypeWellFormedFromEnv(_) => None,
}
});

View File

@ -393,8 +393,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// They can denote both statically and dynamically-sized byte arrays.
let mut pat_ty = ty;
if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(..), .. }) = lt.kind {
if let ty::Ref(_, inner_ty, _) = *self.structurally_resolved_type(span, expected).kind()
&& self.structurally_resolved_type(span, inner_ty).is_slice()
let expected = self.structurally_resolved_type(span, expected);
if let ty::Ref(_, inner_ty, _) = expected.kind()
&& matches!(inner_ty.kind(), ty::Slice(_))
{
let tcx = self.tcx;
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");

View File

@ -739,9 +739,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
self.obligations.push(Obligation {
cause: self.cause.clone(),
param_env: self.param_env,
predicate: ty::Binder::dummy(ty::PredicateKind::Clause(
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(sup, sub)),
))
predicate: ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(sup, sub))
.to_predicate(self.infcx.tcx),
recursion_depth: 0,
});

View File

@ -139,7 +139,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
tcx,
generics,
diag,
&format!("{}", proj.self_ty()),
&proj.self_ty().to_string(),
&path,
None,
matching_span,
@ -153,7 +153,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
tcx,
generics,
diag,
&format!("{}", proj.self_ty()),
&proj.self_ty().to_string(),
&path,
None,
matching_span,

View File

@ -1474,6 +1474,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// universes. Updates `self.universe` to that new universe.
pub fn create_next_universe(&self) -> ty::UniverseIndex {
let u = self.universe.get().next_universe();
debug!("create_next_universe {u:?}");
self.universe.set(u);
u
}

View File

@ -20,27 +20,19 @@ pub fn explicit_outlives_bounds<'tcx>(
param_env
.caller_bounds()
.into_iter()
.map(ty::Predicate::kind)
.map(ty::Clause::kind)
.filter_map(ty::Binder::no_bound_vars)
.filter_map(move |kind| match kind {
ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
| ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
| ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
r_a,
r_b,
))) => Some(OutlivesBound::RegionSubRegion(r_b, r_a)),
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
Some(OutlivesBound::RegionSubRegion(r_b, r_a))
}
ty::ClauseKind::Trait(_)
| ty::ClauseKind::TypeOutlives(_)
| ty::ClauseKind::Projection(_)
| ty::ClauseKind::ConstArgHasType(_, _)
| ty::ClauseKind::WellFormed(_)
| ty::ClauseKind::ConstEvaluatable(_)
| ty::ClauseKind::TypeWellFormedFromEnv(_) => None,
})
}

View File

@ -223,7 +223,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
// parameter environments are already elaborated, so we don't
// have to worry about that.
let c_b = self.param_env.caller_bounds();
let param_bounds = self.collect_outlives_from_predicate_list(erased_ty, c_b.into_iter());
let param_bounds = self.collect_outlives_from_clause_list(erased_ty, c_b.into_iter());
// Next, collect regions we scraped from the well-formedness
// constraints in the fn signature. To do that, we walk the list
@ -307,15 +307,15 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// when comparing `ty` for equality, so `ty` must be something
/// that does not involve inference variables and where you
/// otherwise want a precise match.
fn collect_outlives_from_predicate_list(
fn collect_outlives_from_clause_list(
&self,
erased_ty: Ty<'tcx>,
predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
clauses: impl Iterator<Item = ty::Clause<'tcx>>,
) -> impl Iterator<Item = ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>>
{
let tcx = self.tcx;
let param_env = self.param_env;
predicates.filter_map(|p| p.to_opt_type_outlives()).filter(move |outlives_predicate| {
clauses.filter_map(|p| p.as_type_outlives_clause()).filter(move |outlives_predicate| {
super::test_type_match::can_match_erased_ty(
tcx,
param_env,

View File

@ -258,7 +258,8 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
pred = pred.without_const(tcx);
}
elaboratable.child_with_derived_cause(
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref))
.as_predicate(),
span,
bound_predicate.rebind(data),
index,
@ -367,7 +368,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
.map(|predicate| elaboratable.child(predicate)),
);
}
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {
// Nothing to elaborate
}
ty::PredicateKind::Ambiguous => {}
@ -440,7 +441,7 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>(
tcx.super_predicates_that_define_assoc_item((trait_ref.def_id(), assoc_name));
for (super_predicate, _) in super_predicates.predicates {
let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() {
if let Some(binder) = subst_predicate.as_trait_clause() {
stack.push(binder.map_bound(|t| t.trait_ref));
}
}

View File

@ -14,12 +14,11 @@ use rustc_middle::{bug, ty};
use rustc_parse::maybe_new_parser_from_source_str;
use rustc_query_impl::QueryCtxt;
use rustc_query_system::query::print_query_stack;
use rustc_session::config::{self, ErrorOutputType, Input, OutFileName, OutputFilenames};
use rustc_session::config::{CheckCfg, ExpectedValues};
use rustc_session::lint;
use rustc_session::config::{self, CheckCfg, ExpectedValues, Input, OutFileName, OutputFilenames};
use rustc_session::parse::{CrateConfig, ParseSess};
use rustc_session::CompilerIO;
use rustc_session::Session;
use rustc_session::{early_error, CompilerIO};
use rustc_session::{lint, EarlyErrorHandler};
use rustc_span::source_map::{FileLoader, FileName};
use rustc_span::symbol::sym;
use std::path::PathBuf;
@ -66,7 +65,10 @@ pub fn set_thread_safe_mode(sopts: &config::UnstableOptions) {
}
/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
pub fn parse_cfgspecs(
handler: &EarlyErrorHandler,
cfgspecs: Vec<String>,
) -> FxHashSet<(String, Option<String>)> {
rustc_span::create_default_session_if_not_set_then(move |_| {
let cfg = cfgspecs
.into_iter()
@ -78,10 +80,10 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
macro_rules! error {
($reason: expr) => {
early_error(
ErrorOutputType::default(),
format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s),
);
handler.early_error(format!(
concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
s
));
};
}
@ -125,7 +127,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
}
/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg {
rustc_span::create_default_session_if_not_set_then(move |_| {
let mut check_cfg = CheckCfg::default();
@ -137,10 +139,10 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
macro_rules! error {
($reason: expr) => {
early_error(
ErrorOutputType::default(),
format!(concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), s),
)
handler.early_error(format!(
concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
s
))
};
}
@ -294,8 +296,11 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
let registry = &config.registry;
let handler = EarlyErrorHandler::new(config.opts.error_format);
let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
let (mut sess, codegen_backend) = util::create_session(
&handler,
config.opts,
config.crate_cfg,
config.crate_check_cfg,

View File

@ -21,8 +21,8 @@ use rustc_session::config::{InstrumentCoverage, Passes};
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
use rustc_session::CompilerIO;
use rustc_session::{build_session, getopts, Session};
use rustc_session::{CompilerIO, EarlyErrorHandler};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::symbol::sym;
use rustc_span::FileName;
@ -36,15 +36,18 @@ use std::path::{Path, PathBuf};
type CfgSpecs = FxHashSet<(String, Option<String>)>;
fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options, CfgSpecs) {
let sessopts = build_session_options(&matches);
let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
fn build_session_options_and_crate_config(
handler: &mut EarlyErrorHandler,
matches: getopts::Matches,
) -> (Options, CfgSpecs) {
let sessopts = build_session_options(handler, &matches);
let cfg = parse_cfgspecs(handler, matches.opt_strs("cfg"));
(sessopts, cfg)
}
fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, CfgSpecs) {
let registry = registry::Registry::new(&[]);
let (sessopts, cfg) = build_session_options_and_crate_config(matches);
let (sessopts, cfg) = build_session_options_and_crate_config(handler, matches);
let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
let io = CompilerIO {
input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
@ -52,8 +55,18 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
output_file: None,
temps_dir,
};
let sess =
build_session(sessopts, io, None, registry, vec![], Default::default(), None, None, "");
let sess = build_session(
handler,
sessopts,
io,
None,
registry,
vec![],
Default::default(),
None,
None,
"",
);
(sess, cfg)
}
@ -120,7 +133,8 @@ fn assert_non_crate_hash_different(x: &Options, y: &Options) {
fn test_switch_implies_cfg_test() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["--test".to_string()]).unwrap();
let (sess, cfg) = mk_session(matches);
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let (sess, cfg) = mk_session(&mut handler, matches);
let cfg = build_configuration(&sess, to_crate_config(cfg));
assert!(cfg.contains(&(sym::test, None)));
});
@ -131,7 +145,8 @@ fn test_switch_implies_cfg_test() {
fn test_switch_implies_cfg_test_unless_cfg_test() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
let (sess, cfg) = mk_session(matches);
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let (sess, cfg) = mk_session(&mut handler, matches);
let cfg = build_configuration(&sess, to_crate_config(cfg));
let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
assert!(test_items.next().is_some());
@ -143,20 +158,23 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
fn test_can_print_warnings() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let (sess, _) = mk_session(&mut handler, matches);
assert!(!sess.diagnostic().can_emit_warnings());
});
rustc_span::create_default_session_globals_then(|| {
let matches =
optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let (sess, _) = mk_session(&mut handler, matches);
assert!(sess.diagnostic().can_emit_warnings());
});
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let (sess, _) = mk_session(&mut handler, matches);
assert!(sess.diagnostic().can_emit_warnings());
});
}
@ -302,35 +320,36 @@ fn test_search_paths_tracking_hash_different_order() {
let mut v3 = Options::default();
let mut v4 = Options::default();
let handler = EarlyErrorHandler::new(JSON);
const JSON: ErrorOutputType = ErrorOutputType::Json {
pretty: false,
json_rendered: HumanReadableErrorType::Default(ColorConfig::Never),
};
// Reference
v1.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
v1.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
v1.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
v1.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
v1.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
v1.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
v1.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
v1.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
v1.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
v1.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
v2.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
v2.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
v2.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
v2.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
v2.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
v2.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
v2.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
v2.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
v2.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
v2.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
v3.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
v3.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
v3.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
v3.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
v3.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
v3.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
v3.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
v3.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
v3.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
v3.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
v4.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
v4.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
v4.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
v4.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
v4.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
v4.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
v4.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
v4.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
v4.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
v4.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
assert_same_hash(&v1, &v2);
assert_same_hash(&v1, &v3);
@ -851,7 +870,9 @@ fn test_edition_parsing() {
let options = Options::default();
assert!(options.edition == DEFAULT_EDITION);
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let matches = optgroups().parse(&["--edition=2018".to_string()]).unwrap();
let (sessopts, _) = build_session_options_and_crate_config(matches);
let (sessopts, _) = build_session_options_and_crate_config(&mut handler, matches);
assert!(sessopts.edition == Edition::Edition2018)
}

View File

@ -11,16 +11,16 @@ use rustc_parse::validate_attr;
use rustc_session as session;
use rustc_session::config::CheckCfg;
use rustc_session::config::{self, CrateType};
use rustc_session::config::{ErrorOutputType, OutFileName, OutputFilenames, OutputTypes};
use rustc_session::config::{OutFileName, OutputFilenames, OutputTypes};
use rustc_session::filesearch::sysroot_candidates;
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::CrateConfig;
use rustc_session::{early_error, filesearch, output, Session};
use rustc_session::{filesearch, output, Session};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
use rustc_span::source_map::FileLoader;
use rustc_span::symbol::{sym, Symbol};
use session::CompilerIO;
use session::{CompilerIO, EarlyErrorHandler};
use std::env;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::mem;
@ -58,6 +58,7 @@ pub fn add_configuration(
}
pub fn create_session(
handler: &EarlyErrorHandler,
sopts: config::Options,
cfg: FxHashSet<(String, Option<String>)>,
check_cfg: CheckCfg,
@ -73,7 +74,11 @@ pub fn create_session(
let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
make_codegen_backend(&sopts)
} else {
get_codegen_backend(&sopts.maybe_sysroot, sopts.unstable_opts.codegen_backend.as_deref())
get_codegen_backend(
handler,
&sopts.maybe_sysroot,
sopts.unstable_opts.codegen_backend.as_deref(),
)
};
// target_override is documented to be called before init(), so this is okay
@ -88,7 +93,7 @@ pub fn create_session(
) {
Ok(bundle) => bundle,
Err(e) => {
early_error(sopts.error_format, format!("failed to load fluent bundle: {e}"));
handler.early_error(format!("failed to load fluent bundle: {e}"));
}
};
@ -96,6 +101,7 @@ pub fn create_session(
locale_resources.push(codegen_backend.locale_resource());
let mut sess = session::build_session(
handler,
sopts,
io,
bundle,
@ -218,16 +224,16 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
})
}
fn load_backend_from_dylib(path: &Path) -> MakeBackendFn {
fn load_backend_from_dylib(handler: &EarlyErrorHandler, path: &Path) -> MakeBackendFn {
let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
let err = format!("couldn't load codegen backend {path:?}: {err}");
early_error(ErrorOutputType::default(), err);
handler.early_error(err);
});
let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
.unwrap_or_else(|e| {
let err = format!("couldn't load codegen backend: {e}");
early_error(ErrorOutputType::default(), err);
handler.early_error(err);
});
// Intentionally leak the dynamic library. We can't ever unload it
@ -242,6 +248,7 @@ fn load_backend_from_dylib(path: &Path) -> MakeBackendFn {
///
/// A name of `None` indicates that the default backend should be used.
pub fn get_codegen_backend(
handler: &EarlyErrorHandler,
maybe_sysroot: &Option<PathBuf>,
backend_name: Option<&str>,
) -> Box<dyn CodegenBackend> {
@ -251,10 +258,12 @@ pub fn get_codegen_backend(
let default_codegen_backend = option_env!("CFG_DEFAULT_CODEGEN_BACKEND").unwrap_or("llvm");
match backend_name.unwrap_or(default_codegen_backend) {
filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
filename if filename.contains('.') => {
load_backend_from_dylib(handler, filename.as_ref())
}
#[cfg(feature = "llvm")]
"llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
backend_name => get_codegen_sysroot(maybe_sysroot, backend_name),
backend_name => get_codegen_sysroot(handler, maybe_sysroot, backend_name),
}
});
@ -286,7 +295,11 @@ fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
})
}
fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
fn get_codegen_sysroot(
handler: &EarlyErrorHandler,
maybe_sysroot: &Option<PathBuf>,
backend_name: &str,
) -> MakeBackendFn {
// For now we only allow this function to be called once as it'll dlopen a
// few things, which seems to work best if we only do that once. In
// general this assertion never trips due to the once guard in `get_codegen_backend`,
@ -321,7 +334,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
"failed to find a `codegen-backends` folder \
in the sysroot candidates:\n* {candidates}"
);
early_error(ErrorOutputType::default(), err);
handler.early_error(err);
});
info!("probing {} for a codegen backend", sysroot.display());
@ -332,7 +345,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
sysroot.display(),
e
);
early_error(ErrorOutputType::default(), err);
handler.early_error(err);
});
let mut file: Option<PathBuf> = None;
@ -360,16 +373,16 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
prev.display(),
path.display()
);
early_error(ErrorOutputType::default(), err);
handler.early_error(err);
}
file = Some(path.clone());
}
match file {
Some(ref s) => load_backend_from_dylib(s),
Some(ref s) => load_backend_from_dylib(handler, s),
None => {
let err = format!("unsupported builtin codegen backend `{backend_name}`");
early_error(ErrorOutputType::default(), err);
handler.early_error(err);
}
}
}

View File

@ -1593,33 +1593,25 @@ declare_lint_pass!(
impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
use rustc_middle::ty::ClauseKind;
use rustc_middle::ty::PredicateKind::*;
if cx.tcx.features().trivial_bounds {
let predicates = cx.tcx.predicates_of(item.owner_id);
for &(predicate, span) in predicates.predicates {
let predicate_kind_name = match predicate.kind().skip_binder() {
Clause(ClauseKind::Trait(..)) => "trait",
Clause(ClauseKind::TypeOutlives(..)) |
Clause(ClauseKind::RegionOutlives(..)) => "lifetime",
ClauseKind::Trait(..) => "trait",
ClauseKind::TypeOutlives(..) |
ClauseKind::RegionOutlives(..) => "lifetime",
// `ConstArgHasType` is never global as `ct` is always a param
Clause(ClauseKind::ConstArgHasType(..)) |
ClauseKind::ConstArgHasType(..)
// Ignore projections, as they can only be global
// if the trait bound is global
Clause(ClauseKind::Projection(..)) |
| ClauseKind::Projection(..)
// Ignore bounds that a user can't type
Clause(ClauseKind::WellFormed(..)) |
| ClauseKind::WellFormed(..)
// FIXME(generic_const_exprs): `ConstEvaluatable` can be written
Clause(ClauseKind::ConstEvaluatable(..)) |
AliasRelate(..) |
ObjectSafe(..) |
ClosureKind(..) |
Subtype(..) |
Coerce(..) |
ConstEquate(..) |
Ambiguous |
TypeWellFormedFromEnv(..) => continue,
| ClauseKind::ConstEvaluatable(..)
| ClauseKind::TypeWellFormedFromEnv(_) => continue,
};
if predicate.is_global() {
cx.emit_spanned_lint(

View File

@ -10,7 +10,7 @@ use rustc_errors::{
use rustc_hir::def_id::DefId;
use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{
inhabitedness::InhabitedPredicate, PolyExistentialTraitRef, Predicate, Ty, TyCtxt,
inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt,
};
use rustc_session::parse::ParseSess;
use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol};
@ -352,7 +352,7 @@ impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion {
#[diag(lint_builtin_trivial_bounds)]
pub struct BuiltinTrivialBounds<'a> {
pub predicate_kind_name: &'a str,
pub predicate: Predicate<'a>,
pub predicate: Clause<'a>,
}
#[derive(LintDiagnostic)]
@ -1262,7 +1262,7 @@ pub struct RedundantSemicolonsDiag {
// traits.rs
pub struct DropTraitConstraintsDiag<'a> {
pub predicate: Predicate<'a>,
pub predicate: Clause<'a>,
pub tcx: TyCtxt<'a>,
pub def_id: DefId,
}

View File

@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
.super_predicates_of(def_id)
.predicates
.into_iter()
.filter_map(|(pred, _)| pred.to_opt_poly_trait_pred());
.filter_map(|(pred, _)| pred.as_trait_clause());
if direct_super_traits_iter.count() > 1 {
cx.emit_spanned_lint(
MULTIPLE_SUPERTRAIT_UPCASTABLE,

View File

@ -88,11 +88,10 @@ declare_lint_pass!(
impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
use rustc_middle::ty::ClauseKind;
use rustc_middle::ty::PredicateKind::*;
let predicates = cx.tcx.explicit_predicates_of(item.owner_id);
for &(predicate, span) in predicates.predicates {
let Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() else {
let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else {
continue
};
let def_id = trait_predicate.trait_ref.def_id;

View File

@ -1,5 +1,7 @@
#![deny(unused_must_use)]
use std::cell::RefCell;
use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind};
use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
use crate::diagnostics::utils::SetOnce;
@ -28,6 +30,7 @@ impl<'a> DiagnosticDerive<'a> {
pub(crate) fn into_tokens(self) -> TokenStream {
let DiagnosticDerive { mut structure, mut builder } = self;
let slugs = RefCell::new(Vec::new());
let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
let preamble = builder.preamble(variant);
let body = builder.body(variant);
@ -56,6 +59,7 @@ impl<'a> DiagnosticDerive<'a> {
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
}
Some(slug) => {
slugs.borrow_mut().push(slug.clone());
quote! {
let mut #diag = #handler.struct_diagnostic(crate::fluent_generated::#slug);
}
@ -73,7 +77,8 @@ impl<'a> DiagnosticDerive<'a> {
});
let DiagnosticDeriveKind::Diagnostic { handler } = &builder.kind else { unreachable!() };
structure.gen_impl(quote! {
let mut imp = structure.gen_impl(quote! {
gen impl<'__diagnostic_handler_sess, G>
rustc_errors::IntoDiagnostic<'__diagnostic_handler_sess, G>
for @Self
@ -89,7 +94,11 @@ impl<'a> DiagnosticDerive<'a> {
#implementation
}
}
})
});
for test in slugs.borrow().iter().map(|s| generate_test(s, &structure)) {
imp.extend(test);
}
imp
}
}
@ -124,6 +133,7 @@ impl<'a> LintDiagnosticDerive<'a> {
}
});
let slugs = RefCell::new(Vec::new());
let msg = builder.each_variant(&mut structure, |mut builder, variant| {
// Collect the slug by generating the preamble.
let _ = builder.preamble(variant);
@ -148,6 +158,7 @@ impl<'a> LintDiagnosticDerive<'a> {
DiagnosticDeriveError::ErrorHandled.to_compile_error()
}
Some(slug) => {
slugs.borrow_mut().push(slug.clone());
quote! {
crate::fluent_generated::#slug.into()
}
@ -156,7 +167,7 @@ impl<'a> LintDiagnosticDerive<'a> {
});
let diag = &builder.diag;
structure.gen_impl(quote! {
let mut imp = structure.gen_impl(quote! {
gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
#[track_caller]
fn decorate_lint<'__b>(
@ -171,7 +182,12 @@ impl<'a> LintDiagnosticDerive<'a> {
#msg
}
}
})
});
for test in slugs.borrow().iter().map(|s| generate_test(s, &structure)) {
imp.extend(test);
}
imp
}
}
@ -198,3 +214,40 @@ impl Mismatch {
}
}
}
/// Generates a `#[test]` that verifies that all referenced variables
/// exist on this structure.
fn generate_test(slug: &syn::Path, structure: &Structure<'_>) -> TokenStream {
// FIXME: We can't identify variables in a subdiagnostic
for field in structure.variants().iter().flat_map(|v| v.ast().fields.iter()) {
for attr_name in field.attrs.iter().filter_map(|at| at.path().get_ident()) {
if attr_name == "subdiagnostic" {
return quote!();
}
}
}
use std::sync::atomic::{AtomicUsize, Ordering};
// We need to make sure that the same diagnostic slug can be used multiple times without causing an
// error, so just have a global counter here.
static COUNTER: AtomicUsize = AtomicUsize::new(0);
let slug = slug.get_ident().unwrap();
let ident = quote::format_ident!("verify_{slug}_{}", COUNTER.fetch_add(1, Ordering::Relaxed));
let ref_slug = quote::format_ident!("{slug}_refs");
let struct_name = &structure.ast().ident;
let variables: Vec<_> = structure
.variants()
.iter()
.flat_map(|v| v.ast().fields.iter().filter_map(|f| f.ident.as_ref().map(|i| i.to_string())))
.collect();
// tidy errors on `#[test]` outside of test files, so we use `#[test ]` to work around this
quote! {
#[cfg(test)]
#[test ]
fn #ident() {
let variables = [#(#variables),*];
for vref in crate::fluent_generated::#ref_slug {
assert!(variables.contains(vref), "{}: variable `{vref}` not found ({})", stringify!(#struct_name), stringify!(#slug));
}
}
}
}

View File

@ -636,12 +636,6 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Symbol {
}
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
ty::codec::RefDecodable::decode(d)
}
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] {
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
ty::codec::RefDecodable::decode(d)

View File

@ -83,9 +83,9 @@ macro_rules! arena_types {
rustc_middle::infer::canonical::Canonical<'tcx,
rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::FnSig<'tcx>>
>,
[] type_op_normalize_predicate:
[] type_op_normalize_clause:
rustc_middle::infer::canonical::Canonical<'tcx,
rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Predicate<'tcx>>
rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Clause<'tcx>>
>,
[] type_op_normalize_ty:
rustc_middle::infer::canonical::Canonical<'tcx,

View File

@ -388,10 +388,11 @@ pub fn struct_lint_level(
// it'll become a hard error, so we have to emit *something*. Also,
// if this lint occurs in the expansion of a macro from an external crate,
// allow individual lints to opt-out from being reported.
let not_future_incompatible =
future_incompatible.map(|f| f.reason.edition().is_some()).unwrap_or(true);
if not_future_incompatible && !lint.report_in_external_macro {
let incompatible = future_incompatible.is_some_and(|f| f.reason.edition().is_none());
if !incompatible && !lint.report_in_external_macro {
err.cancel();
// Don't continue further, since we don't want to have
// `diag_span_note_once` called for a diagnostic that isn't emitted.
return;

View File

@ -272,7 +272,8 @@ impl<'tcx> Debug for TerminatorKind<'tcx> {
let unwind = match self.unwind() {
// Not needed or included in successors
None | Some(UnwindAction::Continue) | Some(UnwindAction::Cleanup(_)) => None,
None | Some(UnwindAction::Cleanup(_)) => None,
Some(UnwindAction::Continue) => Some("unwind continue"),
Some(UnwindAction::Unreachable) => Some("unwind unreachable"),
Some(UnwindAction::Terminate) => Some("unwind terminate"),
};

View File

@ -1133,13 +1133,12 @@ macro_rules! visit_place_fns {
fn visit_projection_elem(
&mut self,
local: Local,
proj_base: &[PlaceElem<'tcx>],
place_ref: PlaceRef<'tcx>,
elem: PlaceElem<'tcx>,
context: PlaceContext,
location: Location,
) {
self.super_projection_elem(local, proj_base, elem, context, location);
self.super_projection_elem(place_ref, elem, context, location);
}
fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
@ -1168,15 +1167,13 @@ macro_rules! visit_place_fns {
location: Location,
) {
for (base, elem) in place_ref.iter_projections().rev() {
let base_proj = base.projection;
self.visit_projection_elem(place_ref.local, base_proj, elem, context, location);
self.visit_projection_elem(base, elem, context, location);
}
}
fn super_projection_elem(
&mut self,
_local: Local,
_proj_base: &[PlaceElem<'tcx>],
_place_ref: PlaceRef<'tcx>,
elem: PlaceElem<'tcx>,
_context: PlaceContext,
location: Location,

View File

@ -420,7 +420,7 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
}
}
impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
impl<'tcx> Key for &'tcx ty::List<ty::Clause<'tcx>> {
type CacheSelector = DefaultCacheSelector<Self>;
fn default_span(&self, _: TyCtxt<'_>) -> Span {

View File

@ -2031,10 +2031,10 @@ rustc_queries! {
}
/// Do not call this query directly: part of the `Normalize` type-op
query type_op_normalize_predicate(
goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>>
query type_op_normalize_clause(
goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Clause<'tcx>>
) -> Result<
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>,
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Clause<'tcx>>>,
NoSolution,
> {
desc { "normalizing `{:?}`", goal.value.value.value }
@ -2125,7 +2125,7 @@ rustc_queries! {
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
}
query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Clause<'tcx>>) -> &'tcx ty::List<ty::Clause<'tcx>> {
desc { "revealing opaque types in `{:?}`", key }
}

View File

@ -791,13 +791,6 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
#[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] {
#[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {

View File

@ -410,6 +410,10 @@ pub enum ExprKind<'tcx> {
Return {
value: Option<ExprId>,
},
/// A `become` expression.
Become {
value: ExprId,
},
/// An inline `const` block, e.g. `const {}`.
ConstBlock {
did: DefId,

View File

@ -100,6 +100,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
visitor.visit_expr(&visitor.thir()[value])
}
}
Become { value } => visitor.visit_expr(&visitor.thir()[value]),
ConstBlock { did: _, substs: _ } => {}
Repeat { value, count: _ } => {
visitor.visit_expr(&visitor.thir()[value]);

View File

@ -385,7 +385,7 @@ impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> {
/// A chalk environment and goal.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, TypeVisitable)]
pub struct ChalkEnvironmentAndGoal<'tcx> {
pub environment: &'tcx ty::List<ty::Predicate<'tcx>>,
pub environment: &'tcx ty::List<ty::Clause<'tcx>>,
pub goal: ty::Predicate<'tcx>,
}

View File

@ -25,9 +25,7 @@ impl<'tcx> Elaborator<'tcx> {
.super_predicates_of(trait_ref.def_id())
.predicates
.into_iter()
.flat_map(|(pred, _)| {
pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_pred()
})
.flat_map(|(pred, _)| pred.subst_supertrait(self.tcx, &trait_ref).as_trait_clause())
.map(|t| t.map_bound(|pred| pred.trait_ref))
.filter(|supertrait_ref| self.visited.insert(*supertrait_ref));

View File

@ -368,16 +368,6 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AdtDef<'tcx> {
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
for [(ty::Predicate<'tcx>, Span)]
{
fn decode(decoder: &mut D) -> &'tcx Self {
decoder.interner().arena.alloc_from_iter(
(0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
)
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Span)] {
fn decode(decoder: &mut D) -> &'tcx Self {
decoder.interner().arena.alloc_from_iter(
@ -406,11 +396,11 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Predicate<'tcx>> {
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Clause<'tcx>> {
fn decode(decoder: &mut D) -> &'tcx Self {
let len = decoder.read_usize();
decoder.interner().mk_predicates_from_iter(
(0..len).map::<ty::Predicate<'tcx>, _>(|_| Decodable::decode(decoder)),
decoder.interner().mk_clauses_from_iter(
(0..len).map::<ty::Clause<'tcx>, _>(|_| Decodable::decode(decoder)),
)
}
}
@ -434,7 +424,7 @@ impl_decodable_via_ref! {
&'tcx mir::BorrowCheckResult<'tcx>,
&'tcx mir::coverage::CodeRegion,
&'tcx ty::List<ty::BoundVariableKind>,
&'tcx ty::List<ty::Predicate<'tcx>>,
&'tcx ty::List<ty::Clause<'tcx>>,
&'tcx ty::List<FieldIdx>,
}

View File

@ -141,8 +141,6 @@ pub struct CtxtInterners<'tcx> {
region: InternedSet<'tcx, RegionKind<'tcx>>,
poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
// FIXME(clause): remove this when all usages are moved to predicate
predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
@ -168,7 +166,6 @@ impl<'tcx> CtxtInterners<'tcx> {
poly_existential_predicates: Default::default(),
canonical_var_infos: Default::default(),
predicate: Default::default(),
predicates: Default::default(),
clauses: Default::default(),
projs: Default::default(),
place_elems: Default::default(),
@ -1260,10 +1257,11 @@ nop_lift! {region; Region<'a> => Region<'tcx>}
nop_lift! {const_; Const<'a> => Const<'tcx>}
nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>}
nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
nop_lift! {predicate; Clause<'a> => Clause<'tcx>}
nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>}
nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>}
nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>}
nop_list_lift! {clauses; Clause<'a> => Clause<'tcx>}
nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>}
nop_list_lift! {projs; ProjectionKind => ProjectionKind}
nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind}
@ -1541,7 +1539,6 @@ slice_interners!(
type_lists: pub mk_type_list(Ty<'tcx>),
canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>),
poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>),
predicates: intern_predicates(Predicate<'tcx>),
clauses: intern_clauses(Clause<'tcx>),
projs: pub mk_projs(ProjectionKind),
place_elems: pub mk_place_elems(PlaceElem<'tcx>),
@ -1597,9 +1594,7 @@ impl<'tcx> TyCtxt<'tcx> {
let generic_predicates = self.super_predicates_of(trait_did);
for (predicate, _) in generic_predicates.predicates {
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) =
predicate.kind().skip_binder()
{
if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() {
if set.insert(data.def_id()) {
stack.push(data.def_id());
}
@ -2087,18 +2082,11 @@ impl<'tcx> TyCtxt<'tcx> {
self.intern_poly_existential_predicates(eps)
}
pub fn mk_predicates(self, preds: &[Predicate<'tcx>]) -> &'tcx List<Predicate<'tcx>> {
pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> &'tcx List<Clause<'tcx>> {
// FIXME consider asking the input slice to be sorted to avoid
// re-interning permutations, in which case that would be asserted
// here.
self.intern_predicates(preds)
}
pub fn mk_clauses(self, preds: &[Clause<'tcx>]) -> &'tcx List<Clause<'tcx>> {
// FIXME consider asking the input slice to be sorted to avoid
// re-interning permutations, in which case that would be asserted
// here.
self.intern_clauses(preds)
self.intern_clauses(clauses)
}
pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output
@ -2144,14 +2132,6 @@ impl<'tcx> TyCtxt<'tcx> {
T::collect_and_apply(iter, |xs| self.mk_poly_existential_predicates(xs))
}
pub fn mk_predicates_from_iter<I, T>(self, iter: I) -> T::Output
where
I: Iterator<Item = T>,
T: CollectAndApply<Predicate<'tcx>, &'tcx List<Predicate<'tcx>>>,
{
T::collect_and_apply(iter, |xs| self.mk_predicates(xs))
}
pub fn mk_clauses_from_iter<I, T>(self, iter: I) -> T::Output
where
I: Iterator<Item = T>,

View File

@ -287,7 +287,7 @@ impl FlagComputation {
self.add_const(expected);
self.add_const(found);
}
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(ty)) => {
self.add_ty(ty);
}
ty::PredicateKind::Ambiguous => {}

View File

@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::Span;
use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predicate, TyCtxt};
use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, TyCtxt};
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum GenericParamDefKind {
@ -323,7 +323,7 @@ impl<'tcx> Generics {
#[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)]
pub struct GenericPredicates<'tcx> {
pub parent: Option<DefId>,
pub predicates: &'tcx [(Predicate<'tcx>, Span)],
pub predicates: &'tcx [(Clause<'tcx>, Span)],
}
impl<'tcx> GenericPredicates<'tcx> {
@ -341,8 +341,7 @@ impl<'tcx> GenericPredicates<'tcx> {
&self,
tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>,
) -> impl Iterator<Item = (Predicate<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
{
) -> impl Iterator<Item = (Clause<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator {
EarlyBinder::bind(self.predicates).subst_iter_copied(tcx, substs)
}

View File

@ -62,7 +62,18 @@ impl<'tcx> InhabitedPredicate<'tcx> {
Some(1..) => Ok(false),
},
Self::NotInModule(id) => in_module(id).map(|in_mod| !in_mod),
// `t` may be a projection, for which `inhabited_predicate` returns a `GenericType`. As
// we have a param_env available, we can do better.
Self::GenericType(t) => {
let normalized_pred = tcx
.try_normalize_erasing_regions(param_env, t)
.map_or(self, |t| t.inhabited_predicate(tcx));
match normalized_pred {
// We don't have more information than we started with, so consider inhabited.
Self::GenericType(_) => Ok(true),
pred => pred.apply_inner(tcx, param_env, in_module),
}
}
Self::And([a, b]) => try_and(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
Self::Or([a, b]) => try_or(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
}

View File

@ -555,7 +555,7 @@ impl<'tcx> Predicate<'tcx> {
| PredicateKind::Clause(ClauseKind::ConstEvaluatable(_))
| PredicateKind::ConstEquate(_, _)
| PredicateKind::Ambiguous
| PredicateKind::TypeWellFormedFromEnv(_) => true,
| PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(_)) => true,
}
}
}
@ -566,6 +566,12 @@ impl rustc_errors::IntoDiagnosticArg for Predicate<'_> {
}
}
impl rustc_errors::IntoDiagnosticArg for Clause<'_> {
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
}
}
/// A subset of predicates which can be assumed by the trait solver. They show up in
/// an item's where clauses, hence the name `Clause`, and may either be user-written
/// (such as traits) or may be inserted during lowering.
@ -620,6 +626,10 @@ impl<'tcx> Clause<'tcx> {
None
}
}
pub fn without_const(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
self.as_predicate().without_const(tcx).expect_clause()
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
@ -651,6 +661,11 @@ pub enum ClauseKind<'tcx> {
/// Constant initializer must evaluate successfully.
ConstEvaluatable(ty::Const<'tcx>),
/// Represents a type found in the environment that we can use for implied bounds.
///
/// Only used for Chalk.
TypeWellFormedFromEnv(Ty<'tcx>),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
@ -687,11 +702,6 @@ pub enum PredicateKind<'tcx> {
/// Constants must be equal. The first component is the const that is expected.
ConstEquate(Const<'tcx>, Const<'tcx>),
/// Represents a type found in the environment that we can use for implied bounds.
///
/// Only used for Chalk.
TypeWellFormedFromEnv(Ty<'tcx>),
/// A marker predicate that is always ambiguous.
/// Used for coherence to mark opaque types as possibly equal to each other but ambiguous.
Ambiguous,
@ -730,11 +740,10 @@ pub struct CratePredicatesMap<'tcx> {
/// For each struct with outlive bounds, maps to a vector of the
/// predicate of its outlive bounds. If an item has no outlives
/// bounds, it will have no entry.
// FIXME(clause): should this be a `Clause`?
pub predicates: FxHashMap<DefId, &'tcx [(Clause<'tcx>, Span)]>,
}
impl<'tcx> Predicate<'tcx> {
impl<'tcx> Clause<'tcx> {
/// Performs a substitution suitable for going from a
/// poly-trait-ref to supertraits that must hold if that
/// poly-trait-ref holds. This is slightly different from a normal
@ -744,7 +753,7 @@ impl<'tcx> Predicate<'tcx> {
self,
tcx: TyCtxt<'tcx>,
trait_ref: &ty::PolyTraitRef<'tcx>,
) -> Predicate<'tcx> {
) -> Clause<'tcx> {
// The interaction between HRTB and supertraits is not entirely
// obvious. Let me walk you (and myself) through an example.
//
@ -830,7 +839,13 @@ impl<'tcx> Predicate<'tcx> {
// 3) ['x] + ['b] -> ['x, 'b]
let bound_vars =
tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars));
tcx.reuse_or_mk_predicate(self, ty::Binder::bind_with_vars(new, bound_vars))
// FIXME: Is it really perf sensitive to use reuse_or_mk_predicate here?
tcx.reuse_or_mk_predicate(
self.as_predicate(),
ty::Binder::bind_with_vars(PredicateKind::Clause(new), bound_vars),
)
.expect_clause()
}
}
@ -1301,6 +1316,14 @@ impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitRef<'tcx> {
}
}
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitPredicate<'tcx> {
#[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
let p: Predicate<'tcx> = self.to_predicate(tcx);
p.expect_clause()
}
}
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
#[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
@ -1402,7 +1425,7 @@ impl<'tcx> Predicate<'tcx> {
| PredicateKind::Clause(ClauseKind::ConstEvaluatable(..))
| PredicateKind::ConstEquate(..)
| PredicateKind::Ambiguous
| PredicateKind::TypeWellFormedFromEnv(..) => None,
| PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(..)) => None,
}
}
@ -1423,7 +1446,7 @@ impl<'tcx> Predicate<'tcx> {
| PredicateKind::Clause(ClauseKind::ConstEvaluatable(..))
| PredicateKind::ConstEquate(..)
| PredicateKind::Ambiguous
| PredicateKind::TypeWellFormedFromEnv(..) => None,
| PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(..)) => None,
}
}
@ -1444,7 +1467,7 @@ impl<'tcx> Predicate<'tcx> {
| PredicateKind::Clause(ClauseKind::ConstEvaluatable(..))
| PredicateKind::ConstEquate(..)
| PredicateKind::Ambiguous
| PredicateKind::TypeWellFormedFromEnv(..) => None,
| PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(..)) => None,
}
}
@ -1456,12 +1479,11 @@ impl<'tcx> Predicate<'tcx> {
}
}
/// Turns a predicate into a clause without checking that it is a `PredicateKind::Clause`
/// first. This will ICE when methods are called on `Clause`.
/// Assert that the predicate is a clause.
pub fn expect_clause(self) -> Clause<'tcx> {
match self.kind().skip_binder() {
PredicateKind::Clause(..) => Clause(self.0),
_ => bug!(),
_ => bug!("{self} is not a clause"),
}
}
}
@ -1487,7 +1509,7 @@ impl<'tcx> Predicate<'tcx> {
/// [usize:Bar<isize>]]`.
#[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
pub struct InstantiatedPredicates<'tcx> {
pub predicates: Vec<Predicate<'tcx>>,
pub predicates: Vec<Clause<'tcx>>,
pub spans: Vec<Span>,
}
@ -1506,9 +1528,9 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
}
impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> {
type Item = (Predicate<'tcx>, Span);
type Item = (Clause<'tcx>, Span);
type IntoIter = std::iter::Zip<std::vec::IntoIter<Predicate<'tcx>>, std::vec::IntoIter<Span>>;
type IntoIter = std::iter::Zip<std::vec::IntoIter<Clause<'tcx>>, std::vec::IntoIter<Span>>;
fn into_iter(self) -> Self::IntoIter {
debug_assert_eq!(self.predicates.len(), self.spans.len());
@ -1517,10 +1539,10 @@ impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> {
}
impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> {
type Item = (Predicate<'tcx>, Span);
type Item = (Clause<'tcx>, Span);
type IntoIter = std::iter::Zip<
std::iter::Copied<std::slice::Iter<'a, Predicate<'tcx>>>,
std::iter::Copied<std::slice::Iter<'a, Clause<'tcx>>>,
std::iter::Copied<std::slice::Iter<'a, Span>>,
>;
@ -1670,7 +1692,7 @@ pub struct ParamEnv<'tcx> {
/// want `Reveal::All`.
///
/// Note: This is packed, use the reveal() method to access it.
packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, ParamTag, true>,
packed: CopyTaggedPtr<&'tcx List<Clause<'tcx>>, ParamTag, true>,
}
#[derive(Copy, Clone)]
@ -1736,7 +1758,7 @@ impl<'tcx> ParamEnv<'tcx> {
}
#[inline]
pub fn caller_bounds(self) -> &'tcx List<Predicate<'tcx>> {
pub fn caller_bounds(self) -> &'tcx List<Clause<'tcx>> {
self.packed.pointer()
}
@ -1770,7 +1792,7 @@ impl<'tcx> ParamEnv<'tcx> {
/// Construct a trait environment with the given set of predicates.
#[inline]
pub fn new(
caller_bounds: &'tcx List<Predicate<'tcx>>,
caller_bounds: &'tcx List<Clause<'tcx>>,
reveal: Reveal,
constness: hir::Constness,
) -> Self {

View File

@ -2864,20 +2864,38 @@ define_print_and_forward_display! {
p!(print(binder))
}
ty::Clause<'tcx> {
p!(print(self.kind()))
}
ty::ClauseKind<'tcx> {
match *self {
ty::ClauseKind::Trait(ref data) => {
p!(print(data))
}
ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)),
ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)),
ty::ClauseKind::Projection(predicate) => p!(print(predicate)),
ty::ClauseKind::ConstArgHasType(ct, ty) => {
p!("the constant `", print(ct), "` has type `", print(ty), "`")
},
ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"),
ty::ClauseKind::ConstEvaluatable(ct) => {
p!("the constant `", print(ct), "` can be evaluated")
}
ty::ClauseKind::TypeWellFormedFromEnv(ty) => {
p!("the type `", print(ty), "` is found in the environment")
}
}
}
ty::PredicateKind<'tcx> {
match *self {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref data)) => {
ty::PredicateKind::Clause(data) => {
p!(print(data))
}
ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => p!(print(predicate)),
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => p!(print(predicate)),
ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => p!(print(predicate)),
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
p!("the constant `", print(ct), "` has type `", print(ty), "`")
},
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => p!(print(arg), " well-formed"),
ty::PredicateKind::ObjectSafe(trait_def_id) => {
p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
}
@ -2886,15 +2904,9 @@ define_print_and_forward_display! {
print_value_path(closure_def_id, &[]),
write("` implements the trait `{}`", kind)
),
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
p!("the constant `", print(ct), "` can be evaluated")
}
ty::PredicateKind::ConstEquate(c1, c2) => {
p!("the constant `", print(c1), "` equals `", print(c2), "`")
}
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
p!("the type `", print(ty), "` is found in the environment")
}
ty::PredicateKind::Ambiguous => p!("ambiguous"),
ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
}

View File

@ -189,6 +189,9 @@ impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> {
ty::ClauseKind::ConstEvaluatable(ct) => {
write!(f, "ConstEvaluatable({ct:?})")
}
ty::ClauseKind::TypeWellFormedFromEnv(ty) => {
write!(f, "TypeWellFormedFromEnv({:?})", ty)
}
}
}
}
@ -206,9 +209,6 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
}
ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
write!(f, "TypeWellFormedFromEnv({:?})", ty)
}
ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
ty::PredicateKind::AliasRelate(t1, t2, dir) => {
write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
@ -701,15 +701,6 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
}
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Predicate<'tcx>> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.mk_predicates(v))
}
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Clause<'tcx>> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,

View File

@ -715,7 +715,7 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
/// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
/// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
/// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example).
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> {
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Clause<'tcx> {
use crate::ty::ToPredicate;
match self.skip_binder() {
ExistentialPredicate::Trait(tr) => {

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