commit
9f3c3ffaf8
762 changed files with 14377 additions and 8645 deletions
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
|
|
@ -322,7 +322,7 @@ jobs:
|
|||
NO_DEBUG_ASSERTIONS: 1
|
||||
NO_OVERFLOW_CHECKS: 1
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
os: macos-latest
|
||||
os: macos-12-xl
|
||||
- name: dist-apple-various
|
||||
env:
|
||||
SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim"
|
||||
|
|
@ -333,7 +333,7 @@ jobs:
|
|||
NO_LLVM_ASSERTIONS: 1
|
||||
NO_DEBUG_ASSERTIONS: 1
|
||||
NO_OVERFLOW_CHECKS: 1
|
||||
os: macos-latest
|
||||
os: macos-12-xl
|
||||
- name: dist-x86_64-apple-alt
|
||||
env:
|
||||
SCRIPT: "./x.py dist bootstrap --include-default-paths"
|
||||
|
|
@ -344,7 +344,7 @@ jobs:
|
|||
NO_LLVM_ASSERTIONS: 1
|
||||
NO_DEBUG_ASSERTIONS: 1
|
||||
NO_OVERFLOW_CHECKS: 1
|
||||
os: macos-latest
|
||||
os: macos-12-xl
|
||||
- name: x86_64-apple-1
|
||||
env:
|
||||
SCRIPT: "./x.py --stage 2 test --exclude tests/ui --exclude tests/rustdoc --exclude tests/run-make-fulldeps"
|
||||
|
|
@ -355,7 +355,7 @@ jobs:
|
|||
NO_LLVM_ASSERTIONS: 1
|
||||
NO_DEBUG_ASSERTIONS: 1
|
||||
NO_OVERFLOW_CHECKS: 1
|
||||
os: macos-latest
|
||||
os: macos-12-xl
|
||||
- name: x86_64-apple-2
|
||||
env:
|
||||
SCRIPT: "./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps"
|
||||
|
|
@ -366,7 +366,7 @@ jobs:
|
|||
NO_LLVM_ASSERTIONS: 1
|
||||
NO_DEBUG_ASSERTIONS: 1
|
||||
NO_OVERFLOW_CHECKS: 1
|
||||
os: macos-latest
|
||||
os: macos-12-xl
|
||||
- name: dist-aarch64-apple
|
||||
env:
|
||||
SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2"
|
||||
|
|
@ -381,7 +381,7 @@ jobs:
|
|||
NO_OVERFLOW_CHECKS: 1
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
JEMALLOC_SYS_WITH_LG_PAGE: 14
|
||||
os: macos-latest
|
||||
os: macos-12-xl
|
||||
- name: x86_64-msvc-1
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
|
||||
|
|
|
|||
2
.mailmap
2
.mailmap
|
|
@ -15,7 +15,7 @@ Adrien Tétar <adri-from-59@hotmail.fr>
|
|||
Ahmed Charles <ahmedcharles@gmail.com> <acharles@outlook.com>
|
||||
Alan Egerton <eggyal@gmail.com>
|
||||
Alan Stoate <alan.stoate@gmail.com>
|
||||
Albert Larsan <albert.larsan@gmail.com> Albert Larsan <74931857+albertlarsan68@users.noreply.github.com>
|
||||
Albert Larsan <albert.larsan@gmail.com> <74931857+albertlarsan68@users.noreply.github.com>
|
||||
Alessandro Decina <alessandro.d@gmail.com>
|
||||
Alex Burka <durka42+github@gmail.com> Alex Burka <aburka@seas.upenn.edu>
|
||||
Alex Hansen <ahansen2@trinity.edu>
|
||||
|
|
|
|||
31
Cargo.lock
31
Cargo.lock
|
|
@ -1373,9 +1373,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ena"
|
||||
version = "0.14.0"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
|
||||
checksum = "b2e5d13ca2353ab7d0230988629def93914a8c4015f621f9b13ed2955614731d"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
|
@ -1922,15 +1922,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.0"
|
||||
|
|
@ -2222,14 +2213,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.2"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
|
||||
checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857"
|
||||
dependencies = [
|
||||
"hermit-abi 0.2.6",
|
||||
"hermit-abi 0.3.0",
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys 0.42.0",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2260,9 +2251,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.24"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
|
||||
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
|
@ -2328,9 +2319,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.138"
|
||||
version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
@ -3810,6 +3801,8 @@ dependencies = [
|
|||
"rustc_span",
|
||||
"rustc_symbol_mangling",
|
||||
"rustc_target",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
"tempfile",
|
||||
"tracing",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# The Rust Programming Language
|
||||
|
||||
[](https://www.rust-lang.org/community)
|
||||
|
||||
This is the main source code repository for [Rust]. It contains the compiler,
|
||||
standard library, and documentation.
|
||||
|
||||
|
|
|
|||
|
|
@ -1505,14 +1505,6 @@ pub struct PointeeInfo {
|
|||
pub safe: Option<PointerKind>,
|
||||
}
|
||||
|
||||
/// Used in `might_permit_raw_init` to indicate the kind of initialisation
|
||||
/// that is checked to be valid
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum InitKind {
|
||||
Zero,
|
||||
UninitMitigated0x01Fill,
|
||||
}
|
||||
|
||||
impl LayoutS {
|
||||
/// Returns `true` if the layout corresponds to an unsized type.
|
||||
pub fn is_unsized(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ impl AssocOp {
|
|||
AssignOp(_) | // `{ 42 } +=`
|
||||
As | // `{ 42 } as usize`
|
||||
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
|
||||
// NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
|
||||
// NotEqual | // `{ 42 } != { 42 }` struct literals parser recovery.
|
||||
Colon, // `{ 42 }: usize`
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,9 +22,6 @@ ast_lowering_misplaced_impl_trait =
|
|||
ast_lowering_misplaced_assoc_ty_binding =
|
||||
associated type bounds are only allowed in where clauses and function signatures, not in {$position}
|
||||
|
||||
ast_lowering_rustc_box_attribute_error =
|
||||
#[rustc_box] requires precisely one argument and no other attributes are allowed
|
||||
|
||||
ast_lowering_underscore_expr_lhs_assign =
|
||||
in expressions, `_` can only be used on the left-hand side of an assignment
|
||||
.label = `_` not allowed here
|
||||
|
|
|
|||
|
|
@ -87,13 +87,6 @@ pub struct MisplacedAssocTyBinding<'a> {
|
|||
pub position: DiagnosticArgFromDisplay<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_rustc_box_attribute_error)]
|
||||
pub struct RustcBoxAttributeError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_underscore_expr_lhs_assign)]
|
||||
pub struct UnderscoreExprLhsAssign {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use super::errors::{
|
|||
AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
|
||||
BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt,
|
||||
GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure,
|
||||
RustcBoxAttributeError, UnderscoreExprLhsAssign,
|
||||
UnderscoreExprLhsAssign,
|
||||
};
|
||||
use super::ResolverAstLoweringExt;
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
|
||||
|
|
@ -83,15 +83,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
|
||||
ExprKind::Call(f, args) => {
|
||||
if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) {
|
||||
if let [inner] = &args[..] && e.attrs.len() == 1 {
|
||||
let kind = hir::ExprKind::Box(self.lower_expr(&inner));
|
||||
return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
|
||||
} else {
|
||||
let guar = self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span });
|
||||
hir::ExprKind::Err(guar)
|
||||
}
|
||||
} else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
|
||||
if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
|
||||
self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)
|
||||
} else {
|
||||
let f = self.lower_expr(f);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_hir::def::{DefKind, Res};
|
|||
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_hir::PredicateOrigin;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_middle::ty::{DefIdTree, ResolverAstLowering, TyCtxt};
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
|
|
@ -1339,13 +1339,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
.map(|predicate| self.lower_where_predicate(predicate)),
|
||||
);
|
||||
|
||||
let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> =
|
||||
self.lower_generic_params_mut(&generics.params).collect();
|
||||
let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = self
|
||||
.lower_generic_params_mut(&generics.params, hir::GenericParamSource::Generics)
|
||||
.collect();
|
||||
|
||||
// Introduce extra lifetimes if late resolution tells us to.
|
||||
let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
|
||||
params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
|
||||
self.lifetime_res_to_generic_param(ident, node_id, res)
|
||||
self.lifetime_res_to_generic_param(
|
||||
ident,
|
||||
node_id,
|
||||
res,
|
||||
hir::GenericParamSource::Generics,
|
||||
)
|
||||
}));
|
||||
|
||||
let has_where_clause_predicates = !generics.where_clause.predicates.is_empty();
|
||||
|
|
@ -1449,7 +1455,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
span,
|
||||
}) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
hir_id: self.next_id(),
|
||||
bound_generic_params: self.lower_generic_params(bound_generic_params),
|
||||
bound_generic_params: self
|
||||
.lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder),
|
||||
bounded_ty: self
|
||||
.lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
|
||||
|
|
|
|||
|
|
@ -804,6 +804,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ident: Ident,
|
||||
node_id: NodeId,
|
||||
res: LifetimeRes,
|
||||
source: hir::GenericParamSource,
|
||||
) -> Option<hir::GenericParam<'hir>> {
|
||||
let (name, kind) = match res {
|
||||
LifetimeRes::Param { .. } => {
|
||||
|
|
@ -837,6 +838,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind },
|
||||
colon_span: None,
|
||||
source,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -852,11 +854,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
binder: NodeId,
|
||||
generic_params: &[GenericParam],
|
||||
) -> &'hir [hir::GenericParam<'hir>] {
|
||||
let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect();
|
||||
let mut generic_params: Vec<_> = self
|
||||
.lower_generic_params_mut(generic_params, hir::GenericParamSource::Binder)
|
||||
.collect();
|
||||
let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
|
||||
debug!(?extra_lifetimes);
|
||||
generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
|
||||
self.lifetime_res_to_generic_param(ident, node_id, res)
|
||||
self.lifetime_res_to_generic_param(ident, node_id, res, hir::GenericParamSource::Binder)
|
||||
}));
|
||||
let generic_params = self.arena.alloc_from_iter(generic_params);
|
||||
debug!(?generic_params);
|
||||
|
|
@ -1375,8 +1379,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
span,
|
||||
);
|
||||
let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
|
||||
let (param, bounds, path) =
|
||||
self.lower_generic_and_bounds(*def_node_id, span, ident, bounds);
|
||||
let (param, bounds, path) = self.lower_universal_param_and_bounds(
|
||||
*def_node_id,
|
||||
span,
|
||||
ident,
|
||||
bounds,
|
||||
);
|
||||
self.impl_trait_defs.push(param);
|
||||
if let Some(bounds) = bounds {
|
||||
self.impl_trait_bounds.push(bounds);
|
||||
|
|
@ -1530,6 +1538,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind },
|
||||
colon_span: None,
|
||||
source: hir::GenericParamSource::Generics,
|
||||
}
|
||||
},
|
||||
));
|
||||
|
|
@ -1598,7 +1607,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
|
||||
}
|
||||
|
||||
/// Given a `parent_def_id`, a list of `lifetimes_in_bounds and a `remapping` hash to be
|
||||
/// Given a `parent_def_id`, a list of `lifetimes_in_bounds` and a `remapping` hash to be
|
||||
/// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the
|
||||
/// new definition, adds it to the remapping with the definition of the given lifetime and
|
||||
/// returns a list of lifetimes to be lowered afterwards.
|
||||
|
|
@ -1987,6 +1996,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind },
|
||||
colon_span: None,
|
||||
source: hir::GenericParamSource::Generics,
|
||||
}
|
||||
},
|
||||
));
|
||||
|
|
@ -2152,16 +2162,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn lower_generic_params_mut<'s>(
|
||||
&'s mut self,
|
||||
params: &'s [GenericParam],
|
||||
source: hir::GenericParamSource,
|
||||
) -> impl Iterator<Item = hir::GenericParam<'hir>> + Captures<'a> + Captures<'s> {
|
||||
params.iter().map(move |param| self.lower_generic_param(param))
|
||||
params.iter().map(move |param| self.lower_generic_param(param, source))
|
||||
}
|
||||
|
||||
fn lower_generic_params(&mut self, params: &[GenericParam]) -> &'hir [hir::GenericParam<'hir>] {
|
||||
self.arena.alloc_from_iter(self.lower_generic_params_mut(params))
|
||||
fn lower_generic_params(
|
||||
&mut self,
|
||||
params: &[GenericParam],
|
||||
source: hir::GenericParamSource,
|
||||
) -> &'hir [hir::GenericParam<'hir>] {
|
||||
self.arena.alloc_from_iter(self.lower_generic_params_mut(params, source))
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> {
|
||||
fn lower_generic_param(
|
||||
&mut self,
|
||||
param: &GenericParam,
|
||||
source: hir::GenericParamSource,
|
||||
) -> hir::GenericParam<'hir> {
|
||||
let (name, kind) = self.lower_generic_param_kind(param);
|
||||
|
||||
let hir_id = self.lower_node_id(param.id);
|
||||
|
|
@ -2174,6 +2193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
pure_wrt_drop: self.tcx.sess.contains_name(¶m.attrs, sym::may_dangle),
|
||||
kind,
|
||||
colon_span: param.colon_span.map(|s| self.lower_span(s)),
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2266,7 +2286,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn lower_generic_and_bounds(
|
||||
fn lower_universal_param_and_bounds(
|
||||
&mut self,
|
||||
node_id: NodeId,
|
||||
span: Span,
|
||||
|
|
@ -2286,6 +2306,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
span,
|
||||
kind: hir::GenericParamKind::Type { default: None, synthetic: true },
|
||||
colon_span: None,
|
||||
source: hir::GenericParamSource::Generics,
|
||||
};
|
||||
|
||||
let preds = self.lower_generic_bound_predicate(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
|
|||
use rustc_ast::walk_list;
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_macros::Subdiagnostic;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::lint::builtin::{
|
||||
|
|
@ -192,7 +192,7 @@ impl<'a> AstValidator<'a> {
|
|||
// We allow these:
|
||||
// - `Option<impl Trait>`
|
||||
// - `option::Option<impl Trait>`
|
||||
// - `option::Option<T>::Foo<impl Trait>
|
||||
// - `option::Option<T>::Foo<impl Trait>`
|
||||
//
|
||||
// But not these:
|
||||
// - `<impl Trait>::Foo`
|
||||
|
|
@ -643,7 +643,7 @@ fn validate_generic_param_order(
|
|||
span: Span,
|
||||
) {
|
||||
let mut max_param: Option<ParamKindOrd> = None;
|
||||
let mut out_of_order = FxHashMap::default();
|
||||
let mut out_of_order = FxIndexMap::default();
|
||||
let mut param_idents = Vec::with_capacity(generics.len());
|
||||
|
||||
for (idx, param) in generics.iter().enumerate() {
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
).span_suggestion_verbose(
|
||||
lhs.span.shrink_to_lo(),
|
||||
"you might have meant to introduce a new binding",
|
||||
"let ".to_string(),
|
||||
"let ",
|
||||
Applicability::MachineApplicable,
|
||||
).emit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
//!
|
||||
//! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
|
||||
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_is_partitioned)]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_errors::{
|
|||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
|
||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
|
|
@ -236,10 +236,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let ty = used_place.ty(self.body, self.infcx.tcx).ty;
|
||||
let needs_note = match ty.kind() {
|
||||
ty::Closure(id, _) => {
|
||||
let tables = self.infcx.tcx.typeck(id.expect_local());
|
||||
let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local());
|
||||
|
||||
tables.closure_kind_origins().get(hir_id).is_none()
|
||||
self.infcx.tcx.closure_kind_origin(id.expect_local()).is_none()
|
||||
}
|
||||
_ => true,
|
||||
};
|
||||
|
|
@ -1470,6 +1467,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
/// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
|
||||
///
|
||||
/// Depending on the origin of the StorageDeadOrDrop, this may be
|
||||
/// reported as either a drop or an illegal mutation of a borrowed value.
|
||||
/// The latter is preferred when the this is a drop triggered by a
|
||||
/// reassignment, as it's more user friendly to report a problem with the
|
||||
/// explicit assignment than the implicit drop.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn report_storage_dead_or_drop_of_borrowed(
|
||||
&mut self,
|
||||
location: Location,
|
||||
place_span: (Place<'tcx>, Span),
|
||||
borrow: &BorrowData<'tcx>,
|
||||
) {
|
||||
// It's sufficient to check the last desugaring as Replace is the last
|
||||
// one to be applied.
|
||||
if let Some(DesugaringKind::Replace) = place_span.1.desugaring_kind() {
|
||||
self.report_illegal_mutation_of_borrowed(location, place_span, borrow)
|
||||
} else {
|
||||
self.report_borrowed_value_does_not_live_long_enough(
|
||||
location,
|
||||
borrow,
|
||||
place_span,
|
||||
Some(WriteKind::StorageDeadOrDrop),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// This means that some data referenced by `borrow` needs to live
|
||||
/// past the point where the StorageDeadOrDrop of `place` occurs.
|
||||
/// This is usually interpreted as meaning that `place` has too
|
||||
|
|
@ -1670,7 +1693,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
format!("`{}` would have to be valid for `{}`...", name, region_name),
|
||||
);
|
||||
|
||||
let fn_hir_id = self.mir_hir_id();
|
||||
err.span_label(
|
||||
drop_span,
|
||||
format!(
|
||||
|
|
@ -1678,19 +1700,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
name,
|
||||
self.infcx
|
||||
.tcx
|
||||
.hir()
|
||||
.opt_name(fn_hir_id)
|
||||
.opt_item_name(self.mir_def_id().to_def_id())
|
||||
.map(|name| format!("function `{}`", name))
|
||||
.unwrap_or_else(|| {
|
||||
match &self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck(self.mir_def_id())
|
||||
.node_type(fn_hir_id)
|
||||
.kind()
|
||||
{
|
||||
ty::Closure(..) => "enclosing closure",
|
||||
ty::Generator(..) => "enclosing generator",
|
||||
match &self.infcx.tcx.def_kind(self.mir_def_id()) {
|
||||
DefKind::Closure => "enclosing closure",
|
||||
DefKind::Generator => "enclosing generator",
|
||||
kind => bug!("expected closure or generator, found {:?}", kind),
|
||||
}
|
||||
.to_string()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_middle::mir::{
|
|||
Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::print::Print;
|
||||
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
|
||||
|
|
@ -115,11 +115,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
|
||||
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
|
||||
let did = did.expect_local();
|
||||
let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
|
||||
|
||||
if let Some((span, hir_place)) =
|
||||
self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
|
||||
{
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.span_note(
|
||||
*span,
|
||||
&format!(
|
||||
|
|
@ -139,11 +135,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let Some(target) = target {
|
||||
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
|
||||
let did = did.expect_local();
|
||||
let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
|
||||
|
||||
if let Some((span, hir_place)) =
|
||||
self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
|
||||
{
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.span_note(
|
||||
*span,
|
||||
&format!(
|
||||
|
|
@ -373,14 +365,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
//
|
||||
// We know the field exists so it's safe to call operator[] and `unwrap` here.
|
||||
let def_id = def_id.expect_local();
|
||||
let var_id = self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck(def_id)
|
||||
.closure_min_captures_flattened(def_id)
|
||||
.nth(field.index())
|
||||
.unwrap()
|
||||
.get_root_variable();
|
||||
let var_id =
|
||||
self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable();
|
||||
|
||||
Some(self.infcx.tcx.hir().name(var_id).to_string())
|
||||
}
|
||||
|
|
@ -939,7 +925,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
return OtherUse(use_span);
|
||||
}
|
||||
|
||||
for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
|
||||
// drop and replace might have moved the assignment to the next block
|
||||
let maybe_additional_statement =
|
||||
if let TerminatorKind::Drop { target: drop_target, .. } =
|
||||
self.body[location.block].terminator().kind
|
||||
{
|
||||
self.body[drop_target].statements.first()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let statements =
|
||||
self.body[location.block].statements[location.statement_index + 1..].iter();
|
||||
|
||||
for stmt in statements.chain(maybe_additional_statement) {
|
||||
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
|
||||
let (&def_id, is_generator) = match kind {
|
||||
box AggregateKind::Closure(def_id, _) => (def_id, false),
|
||||
|
|
@ -987,7 +986,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
|
||||
for (captured_place, place) in
|
||||
self.infcx.tcx.typeck(def_id).closure_min_captures_flattened(def_id).zip(places)
|
||||
self.infcx.tcx.closure_captures(def_id).iter().zip(places)
|
||||
{
|
||||
match place {
|
||||
Operand::Copy(place) | Operand::Move(place)
|
||||
|
|
|
|||
|
|
@ -467,7 +467,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
"consider borrowing here",
|
||||
"&".to_string(),
|
||||
'&',
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
err.span_suggestion_verbose(
|
||||
local_decl.source_info.span.shrink_to_lo(),
|
||||
"consider changing this to be mutable",
|
||||
"mut ".to_string(),
|
||||
"mut ",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
let tcx = self.infcx.tcx;
|
||||
|
|
@ -828,7 +828,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let Some(hir::Node::Item(item)) = node else { return; };
|
||||
let hir::ItemKind::Fn(.., body_id) = item.kind else { return; };
|
||||
let body = self.infcx.tcx.hir().body(body_id);
|
||||
let mut v = V { assign_span: span, err, ty, suggested: false };
|
||||
let mut assign_span = span;
|
||||
// Drop desugaring is done at MIR build so it's not in the HIR
|
||||
if let Some(DesugaringKind::Replace) = span.desugaring_kind() {
|
||||
assign_span.remove_mark();
|
||||
}
|
||||
|
||||
let mut v = V { assign_span, err, ty, suggested: false };
|
||||
v.visit_body(body);
|
||||
if !v.suggested {
|
||||
err.help(&format!(
|
||||
|
|
@ -901,10 +907,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
err: &mut Diagnostic,
|
||||
) {
|
||||
let tables = tcx.typeck(closure_local_def_id);
|
||||
let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_local_def_id);
|
||||
if let Some((span, closure_kind_origin)) =
|
||||
&tables.closure_kind_origins().get(closure_hir_id)
|
||||
{
|
||||
if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) {
|
||||
let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base {
|
||||
let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
|
||||
let root_hir_id = upvar_id.var_path.hir_id;
|
||||
|
|
|
|||
|
|
@ -415,7 +415,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
/// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
|
||||
/// ```
|
||||
///
|
||||
/// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
|
||||
/// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`.
|
||||
pub(crate) fn report_region_error(
|
||||
&mut self,
|
||||
fr: RegionVid,
|
||||
|
|
@ -949,7 +949,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
.push_span_label(*span, "this has an implicit `'static` lifetime requirement");
|
||||
multi_span.push_span_label(
|
||||
ident.span,
|
||||
"calling this method introduces the `impl`'s 'static` requirement",
|
||||
"calling this method introduces the `impl`'s `'static` requirement",
|
||||
);
|
||||
err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
|
||||
err.span_suggestion_verbose(
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_middle::ty::print::RegionHighlightMode;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{self, DefIdTree, RegionVid, Ty};
|
||||
use rustc_middle::ty::{self, RegionVid, Ty};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
|
|
|
|||
|
|
@ -202,14 +202,14 @@ fn do_mir_borrowck<'tcx>(
|
|||
let mut errors = error::BorrowckErrors::new(infcx.tcx);
|
||||
|
||||
// Gather the upvars of a closure, if any.
|
||||
let tables = tcx.typeck_opt_const_arg(def);
|
||||
if let Some(e) = tables.tainted_by_errors {
|
||||
if let Some(e) = input_body.tainted_by_errors {
|
||||
infcx.set_tainted_by_errors(e);
|
||||
errors.set_tainted_by_errors(e);
|
||||
}
|
||||
let upvars: Vec<_> = tables
|
||||
.closure_min_captures_flattened(def.did)
|
||||
.map(|captured_place| {
|
||||
let upvars: Vec<_> = tcx
|
||||
.closure_captures(def.did)
|
||||
.iter()
|
||||
.map(|&captured_place| {
|
||||
let capture = captured_place.info.capture_kind;
|
||||
let by_ref = match capture {
|
||||
ty::UpvarCapture::ByValue => false,
|
||||
|
|
@ -1185,12 +1185,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
this.buffer_error(err);
|
||||
}
|
||||
WriteKind::StorageDeadOrDrop => this
|
||||
.report_borrowed_value_does_not_live_long_enough(
|
||||
location,
|
||||
borrow,
|
||||
place_span,
|
||||
Some(kind),
|
||||
),
|
||||
.report_storage_dead_or_drop_of_borrowed(location, place_span, borrow),
|
||||
WriteKind::Mutate => {
|
||||
this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -889,7 +889,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// from a universe it can't name; at present, the only way for
|
||||
/// this to be true is if `scc` outlives `'static`. This is
|
||||
/// actually stricter than necessary: ideally, we'd support bounds
|
||||
/// like `for<'a: 'b`>` that might then allow us to approximate
|
||||
/// like `for<'a: 'b>` that might then allow us to approximate
|
||||
/// `'a` with `'b` and not `'static`. But it will have to do for
|
||||
/// now.
|
||||
fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) {
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ pub(crate) struct RegionValues<N: Idx> {
|
|||
free_regions: SparseBitMatrix<N, RegionVid>,
|
||||
|
||||
/// Placeholders represent bound regions -- so something like `'a`
|
||||
/// in for<'a> fn(&'a u32)`.
|
||||
/// in `for<'a> fn(&'a u32)`.
|
||||
placeholders: SparseBitMatrix<N, PlaceholderIndex>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,11 +26,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
if !self.tcx().is_closure(mir_def_id.to_def_id()) {
|
||||
return;
|
||||
}
|
||||
let Some(user_provided_poly_sig) =
|
||||
self.tcx().typeck(mir_def_id).user_provided_sigs.get(&mir_def_id)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id);
|
||||
|
||||
// Instantiate the canonicalized variables from user-provided signature
|
||||
// (e.g., the `_` in the code above) with fresh variables.
|
||||
|
|
|
|||
|
|
@ -18,13 +18,11 @@ use rustc_errors::Diagnostic;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{BodyOwnerKind, HirId};
|
||||
use rustc_hir::BodyOwnerKind;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{
|
||||
self, DefIdTree, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt,
|
||||
};
|
||||
use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{InternalSubsts, SubstsRef};
|
||||
use rustc_span::Symbol;
|
||||
use std::iter;
|
||||
|
|
@ -231,9 +229,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
mir_def: ty::WithOptConstParam<LocalDefId>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Self {
|
||||
let tcx = infcx.tcx;
|
||||
let mir_hir_id = tcx.hir().local_def_id_to_hir_id(mir_def.did);
|
||||
UniversalRegionsBuilder { infcx, mir_def, mir_hir_id, param_env }.build()
|
||||
UniversalRegionsBuilder { infcx, mir_def, param_env }.build()
|
||||
}
|
||||
|
||||
/// Given a reference to a closure type, extracts all the values
|
||||
|
|
@ -390,7 +386,6 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
struct UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
|
||||
mir_def: ty::WithOptConstParam<LocalDefId>,
|
||||
mir_hir_id: HirId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
|
|
@ -560,12 +555,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
|
||||
match tcx.hir().body_owner_kind(self.mir_def.did) {
|
||||
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
|
||||
let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
|
||||
tcx.type_of(typeck_root_def_id).subst_identity()
|
||||
} else {
|
||||
let tables = tcx.typeck(self.mir_def.did);
|
||||
tables.node_type(self.mir_hir_id)
|
||||
};
|
||||
let defining_ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity();
|
||||
|
||||
debug!("defining_ty (pre-replacement): {:?}", defining_ty);
|
||||
|
||||
|
|
@ -594,7 +584,18 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
|
||||
DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
|
||||
} else {
|
||||
let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
|
||||
// FIXME this line creates a dependency between borrowck and typeck.
|
||||
//
|
||||
// This is required for `AscribeUserType` canonical query, which will call
|
||||
// `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes
|
||||
// into borrowck, which is ICE #78174.
|
||||
//
|
||||
// As a workaround, inline consts have an additional generic param (`ty`
|
||||
// below), so that `type_of(inline_const_def_id).substs(substs)` uses the
|
||||
// proper type with NLL infer vars.
|
||||
let ty = tcx
|
||||
.typeck(self.mir_def.did)
|
||||
.node_type(tcx.local_def_id_to_hir_id(self.mir_def.did));
|
||||
let substs = InlineConstSubsts::new(
|
||||
tcx,
|
||||
InlineConstSubstsParts { parent_substs: identity_substs, ty },
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ pub fn expand_env<'cx>(
|
|||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
let mut exprs = match get_exprs_from_tts(cx, tts) {
|
||||
Some(exprs) if exprs.is_empty() => {
|
||||
Some(exprs) if exprs.is_empty() || exprs.len() > 2 => {
|
||||
cx.span_err(sp, "env! takes 1 or 2 arguments");
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
|
|
@ -64,28 +64,48 @@ pub fn expand_env<'cx>(
|
|||
let Some((var, _style)) = expr_to_string(cx, exprs.next().unwrap(), "expected string literal") else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
let msg = match exprs.next() {
|
||||
None => Symbol::intern(&format!("environment variable `{}` not defined", var)),
|
||||
|
||||
let custom_msg = match exprs.next() {
|
||||
None => None,
|
||||
Some(second) => match expr_to_string(cx, second, "expected string literal") {
|
||||
None => return DummyResult::any(sp),
|
||||
Some((s, _style)) => s,
|
||||
Some((s, _style)) => Some(s),
|
||||
},
|
||||
};
|
||||
|
||||
if exprs.next().is_some() {
|
||||
cx.span_err(sp, "env! takes 1 or 2 arguments");
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
|
||||
let sp = cx.with_def_site_ctxt(sp);
|
||||
let value = env::var(var.as_str()).ok().as_deref().map(Symbol::intern);
|
||||
cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
|
||||
let e = match value {
|
||||
None => {
|
||||
cx.span_err(sp, msg.as_str());
|
||||
let (msg, help) = match custom_msg {
|
||||
None => (
|
||||
format!("environment variable `{var}` not defined at compile time"),
|
||||
Some(help_for_missing_env_var(var.as_str())),
|
||||
),
|
||||
Some(s) => (s.to_string(), None),
|
||||
};
|
||||
let mut diag = cx.struct_span_err(sp, &msg);
|
||||
if let Some(help) = help {
|
||||
diag.help(help);
|
||||
}
|
||||
diag.emit();
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
Some(value) => cx.expr_str(sp, value),
|
||||
};
|
||||
MacEager::expr(e)
|
||||
}
|
||||
|
||||
fn help_for_missing_env_var(var: &str) -> String {
|
||||
if var.starts_with("CARGO_")
|
||||
|| var.starts_with("DEP_")
|
||||
|| matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET")
|
||||
{
|
||||
format!(
|
||||
"Cargo sets build script variables at run time. Use `std::env::var(\"{var}\")` instead"
|
||||
)
|
||||
} else {
|
||||
format!("Use `std::env::var(\"{var}\")` to read the variable at run time")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ mod simd;
|
|||
pub(crate) use cpuid::codegen_cpuid_call;
|
||||
pub(crate) use llvm::codegen_llvm_intrinsic_call;
|
||||
|
||||
use rustc_middle::ty::layout::HasParamEnv;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::{HasParamEnv, ValidityRequirement};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
|
|
@ -627,54 +628,39 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
intrinsic_args!(fx, args => (); intrinsic);
|
||||
|
||||
let ty = substs.type_at(0);
|
||||
let layout = fx.layout_of(ty);
|
||||
if layout.abi.is_uninhabited() {
|
||||
with_no_trimmed_paths!({
|
||||
crate::base::codegen_panic_nounwind(
|
||||
fx,
|
||||
&format!("attempted to instantiate uninhabited type `{}`", layout.ty),
|
||||
source_info,
|
||||
)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if intrinsic == sym::assert_zero_valid
|
||||
&& !fx
|
||||
.tcx
|
||||
.permits_zero_init(fx.param_env().and(ty))
|
||||
.expect("expected to have layout during codegen")
|
||||
{
|
||||
with_no_trimmed_paths!({
|
||||
crate::base::codegen_panic_nounwind(
|
||||
fx,
|
||||
&format!(
|
||||
"attempted to zero-initialize type `{}`, which is invalid",
|
||||
layout.ty
|
||||
),
|
||||
source_info,
|
||||
);
|
||||
});
|
||||
return;
|
||||
}
|
||||
let requirement = ValidityRequirement::from_intrinsic(intrinsic);
|
||||
|
||||
if intrinsic == sym::assert_mem_uninitialized_valid
|
||||
&& !fx
|
||||
if let Some(requirement) = requirement {
|
||||
let do_panic = !fx
|
||||
.tcx
|
||||
.permits_uninit_init(fx.param_env().and(ty))
|
||||
.expect("expected to have layout during codegen")
|
||||
{
|
||||
with_no_trimmed_paths!({
|
||||
crate::base::codegen_panic_nounwind(
|
||||
fx,
|
||||
&format!(
|
||||
"attempted to leave type `{}` uninitialized, which is invalid",
|
||||
layout.ty
|
||||
),
|
||||
source_info,
|
||||
)
|
||||
});
|
||||
return;
|
||||
.check_validity_requirement((requirement, fx.param_env().and(ty)))
|
||||
.expect("expect to have layout during codegen");
|
||||
|
||||
if do_panic {
|
||||
let layout = fx.layout_of(ty);
|
||||
|
||||
with_no_trimmed_paths!({
|
||||
crate::base::codegen_panic_nounwind(
|
||||
fx,
|
||||
&if layout.abi.is_uninhabited() {
|
||||
format!("attempted to instantiate uninhabited type `{}`", layout.ty)
|
||||
} else if requirement == ValidityRequirement::Zero {
|
||||
format!(
|
||||
"attempted to zero-initialize type `{}`, which is invalid",
|
||||
layout.ty
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"attempted to leave type `{}` uninitialized, which is invalid",
|
||||
layout.ty
|
||||
)
|
||||
},
|
||||
source_info,
|
||||
)
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,3 +36,5 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
|||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
tempfile = "3.2.0"
|
||||
serde = { version = "1", features = [ "derive" ]}
|
||||
serde_json = "1"
|
||||
|
|
|
|||
|
|
@ -761,6 +761,7 @@ pub(crate) unsafe fn codegen(
|
|||
EmitObj::None => {}
|
||||
}
|
||||
|
||||
record_llvm_cgu_instructions_stats(&cgcx.prof, llmod);
|
||||
drop(handlers);
|
||||
}
|
||||
|
||||
|
|
@ -974,3 +975,23 @@ fn record_artifact_size(
|
|||
self_profiler_ref.artifact_size(artifact_kind, artifact_name.to_string_lossy(), file_size);
|
||||
}
|
||||
}
|
||||
|
||||
fn record_llvm_cgu_instructions_stats(prof: &SelfProfilerRef, llmod: &llvm::Module) {
|
||||
if !prof.enabled() {
|
||||
return;
|
||||
}
|
||||
|
||||
let raw_stats =
|
||||
llvm::build_string(|s| unsafe { llvm::LLVMRustModuleInstructionStats(&llmod, s) })
|
||||
.expect("cannot get module instruction stats");
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct InstructionsStats {
|
||||
module: String,
|
||||
total: u64,
|
||||
}
|
||||
|
||||
let InstructionsStats { module, total } =
|
||||
serde_json::from_str(&raw_stats).expect("cannot parse llvm cgu instructions stats");
|
||||
prof.artifact_size("cgu_instructions", module, total);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use crate::value::Value;
|
|||
use rustc_ast::Mutability;
|
||||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
|
||||
|
|
@ -252,8 +253,13 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
|
||||
_ => self.static_addr_of(init, alloc.align, None),
|
||||
};
|
||||
if !self.sess().fewer_names() {
|
||||
llvm::set_value_name(value, format!("{:?}", alloc_id).as_bytes());
|
||||
if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty() {
|
||||
let hash = self.tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut hasher = StableHasher::new();
|
||||
alloc.hash_stable(&mut hcx, &mut hasher);
|
||||
hasher.finish::<u128>()
|
||||
});
|
||||
llvm::set_value_name(value, format!("alloc_{hash:032x}").as_bytes());
|
||||
}
|
||||
(value, AddressSpace::DATA)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use super::CodegenUnitDebugContext;
|
|||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
|
||||
use rustc_middle::ty::{self, DefIdTree, Ty};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use trace;
|
||||
|
||||
use crate::common::CodegenCx;
|
||||
|
|
|
|||
|
|
@ -1814,8 +1814,6 @@ extern "C" {
|
|||
/// Creates a legacy pass manager -- only used for final codegen.
|
||||
pub fn LLVMCreatePassManager<'a>() -> &'a mut PassManager<'a>;
|
||||
|
||||
pub fn LLVMInitializePasses();
|
||||
|
||||
pub fn LLVMTimeTraceProfilerInitialize();
|
||||
|
||||
pub fn LLVMTimeTraceProfilerFinishThread();
|
||||
|
|
@ -2410,6 +2408,8 @@ extern "C" {
|
|||
pub fn LLVMRustModuleBufferLen(p: &ModuleBuffer) -> usize;
|
||||
pub fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer);
|
||||
pub fn LLVMRustModuleCost(M: &Module) -> u64;
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString);
|
||||
|
||||
pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool) -> &'static mut ThinLTOBuffer;
|
||||
pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer);
|
||||
|
|
|
|||
|
|
@ -120,8 +120,6 @@ unsafe fn configure_llvm(sess: &Session) {
|
|||
llvm::LLVMTimeTraceProfilerInitialize();
|
||||
}
|
||||
|
||||
llvm::LLVMInitializePasses();
|
||||
|
||||
rustc_llvm::initialize_available_targets();
|
||||
|
||||
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
|
||||
|
|
|
|||
|
|
@ -306,7 +306,13 @@ pub fn create_compressed_metadata_file(
|
|||
symbol_name: &str,
|
||||
) -> Vec<u8> {
|
||||
let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
|
||||
// Our length will be backfilled once we're done writing
|
||||
compressed.write_all(&[0; 4]).unwrap();
|
||||
FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
|
||||
let meta_len = rustc_metadata::METADATA_HEADER.len();
|
||||
let data_len = (compressed.len() - meta_len - 4) as u32;
|
||||
compressed[meta_len..meta_len + 4].copy_from_slice(&data_len.to_be_bytes());
|
||||
|
||||
let Some(mut file) = create_object_file(sess) else {
|
||||
return compressed.to_vec();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_middle::middle::exported_symbols::{
|
|||
use rustc_middle::ty::query::{ExternProviders, Providers};
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::{self, DefIdTree, SymbolName, TyCtxt};
|
||||
use rustc_middle::ty::{self, SymbolName, TyCtxt};
|
||||
use rustc_session::config::{CrateType, OomStrategy};
|
||||
use rustc_target::spec::SanitizerSet;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
|
|||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::mir::mono::Linkage;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self as ty, DefIdTree, TyCtxt};
|
||||
use rustc_middle::ty::{self as ty, TyCtxt};
|
||||
use rustc_session::{lint, parse::feature_err};
|
||||
use rustc_span::{sym, Span};
|
||||
use rustc_target::spec::{abi, SanitizerSet};
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
|||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
|
||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt};
|
||||
use rustc_session::config::OptLevel;
|
||||
|
|
@ -655,41 +655,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// Emit a panic or a no-op for `assert_*` intrinsics.
|
||||
// These are intrinsics that compile to panics so that we can get a message
|
||||
// which mentions the offending type, even from a const context.
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum AssertIntrinsic {
|
||||
Inhabited,
|
||||
ZeroValid,
|
||||
MemUninitializedValid,
|
||||
}
|
||||
let panic_intrinsic = intrinsic.and_then(|i| match i {
|
||||
sym::assert_inhabited => Some(AssertIntrinsic::Inhabited),
|
||||
sym::assert_zero_valid => Some(AssertIntrinsic::ZeroValid),
|
||||
sym::assert_mem_uninitialized_valid => Some(AssertIntrinsic::MemUninitializedValid),
|
||||
_ => None,
|
||||
});
|
||||
if let Some(intrinsic) = panic_intrinsic {
|
||||
use AssertIntrinsic::*;
|
||||
|
||||
let panic_intrinsic = intrinsic.and_then(|s| ValidityRequirement::from_intrinsic(s));
|
||||
if let Some(requirement) = panic_intrinsic {
|
||||
let ty = instance.unwrap().substs.type_at(0);
|
||||
|
||||
let do_panic = !bx
|
||||
.tcx()
|
||||
.check_validity_requirement((requirement, bx.param_env().and(ty)))
|
||||
.expect("expect to have layout during codegen");
|
||||
|
||||
let layout = bx.layout_of(ty);
|
||||
let do_panic = match intrinsic {
|
||||
Inhabited => layout.abi.is_uninhabited(),
|
||||
ZeroValid => !bx
|
||||
.tcx()
|
||||
.permits_zero_init(bx.param_env().and(ty))
|
||||
.expect("expected to have layout during codegen"),
|
||||
MemUninitializedValid => !bx
|
||||
.tcx()
|
||||
.permits_uninit_init(bx.param_env().and(ty))
|
||||
.expect("expected to have layout during codegen"),
|
||||
};
|
||||
|
||||
Some(if do_panic {
|
||||
let msg_str = with_no_visible_paths!({
|
||||
with_no_trimmed_paths!({
|
||||
if layout.abi.is_uninhabited() {
|
||||
// Use this error even for the other intrinsics as it is more precise.
|
||||
format!("attempted to instantiate uninhabited type `{}`", ty)
|
||||
} else if intrinsic == ZeroValid {
|
||||
} else if requirement == ValidityRequirement::Zero {
|
||||
format!("attempted to zero-initialize type `{}`, which is invalid", ty)
|
||||
} else {
|
||||
format!(
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{DefIdTree, TyCtxt};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
|
|
@ -185,7 +185,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
|||
("avx512vpopcntdq", Some(sym::avx512_target_feature)),
|
||||
("bmi1", None),
|
||||
("bmi2", None),
|
||||
("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
|
||||
("cmpxchg16b", None),
|
||||
("ermsb", Some(sym::ermsb_target_feature)),
|
||||
("f16c", None),
|
||||
("fma", None),
|
||||
|
|
@ -394,7 +394,6 @@ pub fn from_target_feature(
|
|||
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
|
||||
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
|
||||
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
|
||||
Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
|
||||
Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
|
||||
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
|
||||
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{DefIdTree, TyCtxt};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_middle::mir::{
|
|||
BinOp, NonDivergingIntrinsic,
|
||||
};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::LayoutOf as _;
|
||||
use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
|
@ -418,54 +418,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
| sym::assert_zero_valid
|
||||
| sym::assert_mem_uninitialized_valid => {
|
||||
let ty = instance.substs.type_at(0);
|
||||
let layout = self.layout_of(ty)?;
|
||||
let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap();
|
||||
|
||||
// For *all* intrinsics we first check `is_uninhabited` to give a more specific
|
||||
// error message.
|
||||
if layout.abi.is_uninhabited() {
|
||||
// The run-time intrinsic panics just to get a good backtrace; here we abort
|
||||
// since there is no problem showing a backtrace even for aborts.
|
||||
M::abort(
|
||||
self,
|
||||
format!(
|
||||
let should_panic = !self
|
||||
.tcx
|
||||
.check_validity_requirement((requirement, self.param_env.and(ty)))
|
||||
.map_err(|_| err_inval!(TooGeneric))?;
|
||||
|
||||
if should_panic {
|
||||
let layout = self.layout_of(ty)?;
|
||||
|
||||
let msg = match requirement {
|
||||
// For *all* intrinsics we first check `is_uninhabited` to give a more specific
|
||||
// error message.
|
||||
_ if layout.abi.is_uninhabited() => format!(
|
||||
"aborted execution: attempted to instantiate uninhabited type `{}`",
|
||||
ty
|
||||
),
|
||||
)?;
|
||||
}
|
||||
ValidityRequirement::Inhabited => bug!("handled earlier"),
|
||||
ValidityRequirement::Zero => format!(
|
||||
"aborted execution: attempted to zero-initialize type `{}`, which is invalid",
|
||||
ty
|
||||
),
|
||||
ValidityRequirement::UninitMitigated0x01Fill => format!(
|
||||
"aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
|
||||
ty
|
||||
),
|
||||
ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"),
|
||||
};
|
||||
|
||||
if intrinsic_name == sym::assert_zero_valid {
|
||||
let should_panic = !self
|
||||
.tcx
|
||||
.permits_zero_init(self.param_env.and(ty))
|
||||
.map_err(|_| err_inval!(TooGeneric))?;
|
||||
|
||||
if should_panic {
|
||||
M::abort(
|
||||
self,
|
||||
format!(
|
||||
"aborted execution: attempted to zero-initialize type `{}`, which is invalid",
|
||||
ty
|
||||
),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
if intrinsic_name == sym::assert_mem_uninitialized_valid {
|
||||
let should_panic = !self
|
||||
.tcx
|
||||
.permits_uninit_init(self.param_env.and(ty))
|
||||
.map_err(|_| err_inval!(TooGeneric))?;
|
||||
|
||||
if should_panic {
|
||||
M::abort(
|
||||
self,
|
||||
format!(
|
||||
"aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
|
||||
ty
|
||||
),
|
||||
)?;
|
||||
}
|
||||
M::abort(self, msg)?;
|
||||
}
|
||||
}
|
||||
sym::simd_insert => {
|
||||
|
|
@ -476,7 +458,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
assert_eq!(input_len, dest_len, "Return vector length must match input length");
|
||||
assert!(
|
||||
index < dest_len,
|
||||
"Index `{}` must be in bounds of vector with length {}`",
|
||||
"Index `{}` must be in bounds of vector with length {}",
|
||||
index,
|
||||
dest_len
|
||||
);
|
||||
|
|
@ -496,7 +478,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let (input, input_len) = self.operand_to_simd(&args[0])?;
|
||||
assert!(
|
||||
index < input_len,
|
||||
"index `{}` must be in bounds of vector with length `{}`",
|
||||
"index `{}` must be in bounds of vector with length {}",
|
||||
index,
|
||||
input_len
|
||||
);
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ use rustc_target::spec::abi::Abi as CallAbi;
|
|||
use crate::const_eval::CheckAlignment;
|
||||
|
||||
use super::{
|
||||
AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
|
||||
MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
|
||||
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx,
|
||||
InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
|
||||
};
|
||||
|
||||
/// Data returned by Machine::stack_pop,
|
||||
|
|
@ -105,10 +105,16 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||
/// Extra data stored in every allocation.
|
||||
type AllocExtra: Debug + Clone + 'static;
|
||||
|
||||
/// Type for the bytes of the allocation.
|
||||
type Bytes: AllocBytes + 'static;
|
||||
|
||||
/// Memory's allocation map
|
||||
type MemoryMap: AllocMap<
|
||||
AllocId,
|
||||
(MemoryKind<Self::MemoryKind>, Allocation<Self::Provenance, Self::AllocExtra>),
|
||||
(
|
||||
MemoryKind<Self::MemoryKind>,
|
||||
Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>,
|
||||
),
|
||||
> + Default
|
||||
+ Clone;
|
||||
|
||||
|
|
@ -338,7 +344,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||
id: AllocId,
|
||||
alloc: Cow<'b, Allocation>,
|
||||
kind: Option<MemoryKind<Self::MemoryKind>>,
|
||||
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra>>>;
|
||||
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>;
|
||||
|
||||
fn eval_inline_asm(
|
||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
|
|
@ -459,6 +465,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
|||
|
||||
type AllocExtra = ();
|
||||
type FrameExtra = ();
|
||||
type Bytes = Box<[u8]>;
|
||||
|
||||
#[inline(always)]
|
||||
fn use_addr_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ use rustc_target::abi::{Align, HasDataLayout, Size};
|
|||
use crate::const_eval::CheckAlignment;
|
||||
|
||||
use super::{
|
||||
alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, InterpCx,
|
||||
InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar,
|
||||
alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg,
|
||||
GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance,
|
||||
Scalar,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
|
|
@ -114,16 +115,16 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
|
|||
/// A reference to some allocation that was already bounds-checked for the given region
|
||||
/// and had the on-access machine hooks run.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AllocRef<'a, 'tcx, Prov: Provenance, Extra> {
|
||||
alloc: &'a Allocation<Prov, Extra>,
|
||||
pub struct AllocRef<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes = Box<[u8]>> {
|
||||
alloc: &'a Allocation<Prov, Extra, Bytes>,
|
||||
range: AllocRange,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
alloc_id: AllocId,
|
||||
}
|
||||
/// A reference to some allocation that was already bounds-checked for the given region
|
||||
/// and had the on-access machine hooks run.
|
||||
pub struct AllocRefMut<'a, 'tcx, Prov: Provenance, Extra> {
|
||||
alloc: &'a mut Allocation<Prov, Extra>,
|
||||
pub struct AllocRefMut<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes = Box<[u8]>> {
|
||||
alloc: &'a mut Allocation<Prov, Extra, Bytes>,
|
||||
range: AllocRange,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
alloc_id: AllocId,
|
||||
|
|
@ -483,7 +484,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
&self,
|
||||
id: AllocId,
|
||||
is_write: bool,
|
||||
) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::Provenance, M::AllocExtra>>> {
|
||||
) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::Provenance, M::AllocExtra, M::Bytes>>> {
|
||||
let (alloc, def_id) = match self.tcx.try_get_global_alloc(id) {
|
||||
Some(GlobalAlloc::Memory(mem)) => {
|
||||
// Memory of a constant or promoted or anonymous memory referenced by a static.
|
||||
|
|
@ -526,6 +527,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Get the base address for the bytes in an `Allocation` specified by the
|
||||
/// `AllocID` passed in; error if no such allocation exists.
|
||||
///
|
||||
/// It is up to the caller to take sufficient care when using this address:
|
||||
/// there could be provenance or uninit memory in there, and other memory
|
||||
/// accesses could invalidate the exposed pointer.
|
||||
pub fn alloc_base_addr(&self, id: AllocId) -> InterpResult<'tcx, *const u8> {
|
||||
let alloc = self.get_alloc_raw(id)?;
|
||||
Ok(alloc.base_addr())
|
||||
}
|
||||
|
||||
/// Gives raw access to the `Allocation`, without bounds or alignment checks.
|
||||
/// The caller is responsible for calling the access hooks!
|
||||
///
|
||||
|
|
@ -533,7 +545,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
fn get_alloc_raw(
|
||||
&self,
|
||||
id: AllocId,
|
||||
) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra>> {
|
||||
) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra, M::Bytes>> {
|
||||
// The error type of the inner closure here is somewhat funny. We have two
|
||||
// ways of "erroring": An actual error, or because we got a reference from
|
||||
// `get_global_alloc` that we can actually use directly without inserting anything anywhere.
|
||||
|
|
@ -569,7 +581,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
ptr: Pointer<Option<M::Provenance>>,
|
||||
size: Size,
|
||||
align: Align,
|
||||
) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra>>> {
|
||||
) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
|
||||
{
|
||||
let ptr_and_alloc = self.check_and_deref_ptr(
|
||||
ptr,
|
||||
size,
|
||||
|
|
@ -612,7 +625,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
fn get_alloc_raw_mut(
|
||||
&mut self,
|
||||
id: AllocId,
|
||||
) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra>, &mut M)> {
|
||||
) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra, M::Bytes>, &mut M)> {
|
||||
// We have "NLL problem case #3" here, which cannot be worked around without loss of
|
||||
// efficiency even for the common case where the key is in the map.
|
||||
// <https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions>
|
||||
|
|
@ -641,7 +654,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
ptr: Pointer<Option<M::Provenance>>,
|
||||
size: Size,
|
||||
align: Align,
|
||||
) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra>>> {
|
||||
) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
|
||||
{
|
||||
let parts = self.get_ptr_access(ptr, size, align)?;
|
||||
if let Some((alloc_id, offset, prov)) = parts {
|
||||
let tcx = *self.tcx;
|
||||
|
|
@ -840,11 +854,11 @@ pub struct DumpAllocs<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
|
|||
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, 'mir, 'tcx, M> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Cannot be a closure because it is generic in `Prov`, `Extra`.
|
||||
fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra>(
|
||||
fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>(
|
||||
fmt: &mut std::fmt::Formatter<'_>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
allocs_to_print: &mut VecDeque<AllocId>,
|
||||
alloc: &Allocation<Prov, Extra>,
|
||||
alloc: &Allocation<Prov, Extra, Bytes>,
|
||||
) -> std::fmt::Result {
|
||||
for alloc_id in alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id())
|
||||
{
|
||||
|
|
@ -912,7 +926,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
|
|||
}
|
||||
|
||||
/// Reading and writing.
|
||||
impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> {
|
||||
impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes>
|
||||
AllocRefMut<'a, 'tcx, Prov, Extra, Bytes>
|
||||
{
|
||||
/// `range` is relative to this allocation reference, not the base of the allocation.
|
||||
pub fn write_scalar(&mut self, range: AllocRange, val: Scalar<Prov>) -> InterpResult<'tcx> {
|
||||
let range = self.range.subrange(range);
|
||||
|
|
@ -937,7 +953,7 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> {
|
||||
impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Prov, Extra, Bytes> {
|
||||
/// `range` is relative to this allocation reference, not the base of the allocation.
|
||||
pub fn read_scalar(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -353,7 +353,8 @@ where
|
|||
pub(super) fn get_place_alloc(
|
||||
&self,
|
||||
place: &MPlaceTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra>>> {
|
||||
) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
|
||||
{
|
||||
assert!(place.layout.is_sized());
|
||||
assert!(!place.meta.has_meta());
|
||||
let size = place.layout.size;
|
||||
|
|
@ -364,7 +365,8 @@ where
|
|||
pub(super) fn get_place_alloc_mut(
|
||||
&mut self,
|
||||
place: &MPlaceTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra>>> {
|
||||
) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
|
||||
{
|
||||
assert!(place.layout.is_sized());
|
||||
assert!(!place.meta.has_meta());
|
||||
let size = place.layout.size;
|
||||
|
|
|
|||
|
|
@ -240,10 +240,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
// FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar
|
||||
// https://github.com/rust-lang/project-rfc-2229/issues/46
|
||||
if let Some(local_def_id) = def_id.as_local() {
|
||||
let tables = self.ecx.tcx.typeck(local_def_id);
|
||||
if let Some(captured_place) =
|
||||
tables.closure_min_captures_flattened(local_def_id).nth(field)
|
||||
{
|
||||
let captures = self.ecx.tcx.closure_captures(local_def_id);
|
||||
if let Some(captured_place) = captures.get(field) {
|
||||
// Sometimes the index is beyond the number of upvars (seen
|
||||
// for a generator).
|
||||
let var_hir_id = captured_place.get_root_variable();
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
|
|||
use rustc_macros::fluent_messages;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_target::abi::InitKind;
|
||||
|
||||
fluent_messages! { "../locales/en-US.ftl" }
|
||||
|
||||
|
|
@ -62,9 +61,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
let (param_env, value) = param_env_and_value.into_parts();
|
||||
const_eval::deref_mir_constant(tcx, param_env, value)
|
||||
};
|
||||
providers.permits_uninit_init = |tcx, param_env_and_ty| {
|
||||
util::might_permit_raw_init(tcx, param_env_and_ty, InitKind::UninitMitigated0x01Fill)
|
||||
providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
|
||||
util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
|
||||
};
|
||||
providers.permits_zero_init =
|
||||
|tcx, param_env_and_ty| util::might_permit_raw_init(tcx, param_env_and_ty, InitKind::Zero);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
|
||||
fn check_static(&mut self, def_id: DefId, span: Span) {
|
||||
if self.tcx.is_thread_local_static(def_id) {
|
||||
self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef");
|
||||
self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`");
|
||||
}
|
||||
self.check_op_spanned(ops::StaticAccess, span)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
|
|||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{
|
||||
suggest_constraining_type_param, Adt, Closure, DefIdTree, FnDef, FnPtr, Param, Ty,
|
||||
};
|
||||
use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty};
|
||||
use rustc_middle::ty::{Binder, TraitRef};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::sym;
|
||||
|
|
|
|||
|
|
@ -755,8 +755,26 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
self.fail(location, format!("explicit `{:?}` is forbidden", kind));
|
||||
}
|
||||
}
|
||||
StatementKind::StorageLive(..)
|
||||
| StatementKind::StorageDead(..)
|
||||
StatementKind::StorageLive(local) => {
|
||||
// We check that the local is not live when entering a `StorageLive` for it.
|
||||
// Technically, violating this restriction is only UB and not actually indicative
|
||||
// of not well-formed MIR. This means that an optimization which turns MIR that
|
||||
// already has UB into MIR that fails this check is not necessarily wrong. However,
|
||||
// we have no such optimizations at the moment, and so we include this check anyway
|
||||
// to help us catch bugs. If you happen to write an optimization that might cause
|
||||
// this to incorrectly fire, feel free to remove this check.
|
||||
if self.reachable_blocks.contains(location.block) {
|
||||
self.storage_liveness.seek_before_primary_effect(location);
|
||||
let locals_with_storage = self.storage_liveness.get();
|
||||
if locals_with_storage.contains(*local) {
|
||||
self.fail(
|
||||
location,
|
||||
format!("StorageLive({local:?}) which already has storage here"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
StatementKind::StorageDead(_)
|
||||
| StatementKind::Coverage(_)
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::Nop => {}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
|
||||
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_session::Limit;
|
||||
use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
|
||||
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
|
||||
|
||||
use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
|
||||
use crate::interpret::{InterpCx, MemoryKind, OpTy};
|
||||
|
|
@ -18,16 +18,23 @@ use crate::interpret::{InterpCx, MemoryKind, OpTy};
|
|||
/// Rust UB as long as there is no risk of miscompilations. The `strict_init_checks` can be set to
|
||||
/// do a full check against Rust UB instead (in which case we will also ignore the 0x01-filling and
|
||||
/// to the full uninit check).
|
||||
pub fn might_permit_raw_init<'tcx>(
|
||||
pub fn check_validity_requirement<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
kind: ValidityRequirement,
|
||||
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
kind: InitKind,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
if tcx.sess.opts.unstable_opts.strict_init_checks {
|
||||
might_permit_raw_init_strict(tcx.layout_of(param_env_and_ty)?, tcx, kind)
|
||||
let layout = tcx.layout_of(param_env_and_ty)?;
|
||||
|
||||
// There is nothing strict or lax about inhabitedness.
|
||||
if kind == ValidityRequirement::Inhabited {
|
||||
return Ok(!layout.abi.is_uninhabited());
|
||||
}
|
||||
|
||||
if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks {
|
||||
might_permit_raw_init_strict(layout, tcx, kind)
|
||||
} else {
|
||||
let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env };
|
||||
might_permit_raw_init_lax(tcx.layout_of(param_env_and_ty)?, &layout_cx, kind)
|
||||
might_permit_raw_init_lax(layout, &layout_cx, kind)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +43,7 @@ pub fn might_permit_raw_init<'tcx>(
|
|||
fn might_permit_raw_init_strict<'tcx>(
|
||||
ty: TyAndLayout<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
kind: InitKind,
|
||||
kind: ValidityRequirement,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
let machine = CompileTimeInterpreter::new(
|
||||
Limit::new(0),
|
||||
|
|
@ -50,7 +57,7 @@ fn might_permit_raw_init_strict<'tcx>(
|
|||
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
|
||||
.expect("OOM: failed to allocate for uninit check");
|
||||
|
||||
if kind == InitKind::Zero {
|
||||
if kind == ValidityRequirement::Zero {
|
||||
cx.write_bytes_ptr(
|
||||
allocated.ptr,
|
||||
std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
|
||||
|
|
@ -72,15 +79,18 @@ fn might_permit_raw_init_strict<'tcx>(
|
|||
fn might_permit_raw_init_lax<'tcx>(
|
||||
this: TyAndLayout<'tcx>,
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
init_kind: InitKind,
|
||||
init_kind: ValidityRequirement,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
let scalar_allows_raw_init = move |s: Scalar| -> bool {
|
||||
match init_kind {
|
||||
InitKind::Zero => {
|
||||
ValidityRequirement::Inhabited => {
|
||||
bug!("ValidityRequirement::Inhabited should have been handled above")
|
||||
}
|
||||
ValidityRequirement::Zero => {
|
||||
// The range must contain 0.
|
||||
s.valid_range(cx).contains(0)
|
||||
}
|
||||
InitKind::UninitMitigated0x01Fill => {
|
||||
ValidityRequirement::UninitMitigated0x01Fill => {
|
||||
// The range must include an 0x01-filled buffer.
|
||||
let mut val: u128 = 0x01;
|
||||
for _ in 1..s.size(cx).bytes() {
|
||||
|
|
@ -89,6 +99,9 @@ fn might_permit_raw_init_lax<'tcx>(
|
|||
}
|
||||
s.valid_range(cx).contains(val)
|
||||
}
|
||||
ValidityRequirement::Uninit => {
|
||||
bug!("ValidityRequirement::Uninit should have been handled above")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
mod alignment;
|
||||
mod call_kind;
|
||||
mod check_validity_requirement;
|
||||
pub mod collect_writes;
|
||||
mod compare_types;
|
||||
mod find_self_call;
|
||||
mod might_permit_raw_init;
|
||||
mod type_name;
|
||||
|
||||
pub use self::alignment::is_disaligned;
|
||||
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
|
||||
pub use self::check_validity_requirement::check_validity_requirement;
|
||||
pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
|
||||
pub use self::find_self_call::find_self_call;
|
||||
pub use self::might_permit_raw_init::might_permit_raw_init;
|
||||
pub use self::type_name::type_name;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ edition = "2021"
|
|||
arrayvec = { version = "0.7", default-features = false }
|
||||
bitflags = "1.2.1"
|
||||
cfg-if = "1.0"
|
||||
ena = "0.14"
|
||||
ena = "0.14.1"
|
||||
indexmap = { version = "1.9.1" }
|
||||
jobserver_crate = { version = "0.1.13", package = "jobserver" }
|
||||
libc = "0.2"
|
||||
|
|
|
|||
|
|
@ -426,6 +426,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||
// nodes. Therefore we use a `while` loop.
|
||||
let mut index = 0;
|
||||
while let Some(node) = self.nodes.get_mut(index) {
|
||||
// This test is extremely hot.
|
||||
if node.state.get() != NodeState::Pending
|
||||
|| !processor.needs_process_obligation(&node.obligation)
|
||||
{
|
||||
|
|
@ -439,6 +440,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||
// out of sync with `nodes`. It's not very common, but it does
|
||||
// happen, and code in `compress` has to allow for it.
|
||||
|
||||
// This code is much less hot.
|
||||
match processor.process_obligation(&mut node.obligation) {
|
||||
ProcessResult::Unchanged => {
|
||||
// No change in state.
|
||||
|
|
|
|||
|
|
@ -100,6 +100,11 @@ impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> {
|
|||
(k == &key).then_some((i, v))
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains_key(&self, key: K) -> bool {
|
||||
self.get_by_key(key).next().is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Idx, K: Eq, V: Eq> Eq for SortedIndexMultiMap<I, K, V> {}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ fn test_sorted_index_multi_map() {
|
|||
assert_eq!(set.get_by_key(3).copied().collect::<Vec<_>>(), vec![0]);
|
||||
assert!(set.get_by_key(4).next().is_none());
|
||||
|
||||
// `contains_key` works
|
||||
assert!(set.contains_key(3));
|
||||
assert!(!set.contains_key(4));
|
||||
|
||||
// `get_by_key` returns items in insertion order.
|
||||
let twos: Vec<_> = set.get_by_key_enumerated(2).collect();
|
||||
let idxs: Vec<usize> = twos.iter().map(|(i, _)| *i).collect();
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ fn test_isize_compression() {
|
|||
let hash_b = hash(&(b as isize, a as isize));
|
||||
assert_ne!(
|
||||
hash_a, hash_b,
|
||||
"The hash stayed the same when permuting values `{a}` and `{b}!",
|
||||
"The hash stayed the same when permuting values `{a}` and `{b}`!",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1895,7 +1895,7 @@ impl EmitterWriter {
|
|||
self.draw_code_line(
|
||||
&mut buffer,
|
||||
&mut row_num,
|
||||
&Vec::new(),
|
||||
&[],
|
||||
p + line_start,
|
||||
l,
|
||||
show_code_change,
|
||||
|
|
@ -1919,7 +1919,7 @@ impl EmitterWriter {
|
|||
self.draw_code_line(
|
||||
&mut buffer,
|
||||
&mut row_num,
|
||||
&Vec::new(),
|
||||
&[],
|
||||
p + line_start,
|
||||
l,
|
||||
show_code_change,
|
||||
|
|
@ -1936,7 +1936,7 @@ impl EmitterWriter {
|
|||
self.draw_code_line(
|
||||
&mut buffer,
|
||||
&mut row_num,
|
||||
&Vec::new(),
|
||||
&[],
|
||||
p + line_start,
|
||||
l,
|
||||
show_code_change,
|
||||
|
|
@ -1951,7 +1951,7 @@ impl EmitterWriter {
|
|||
self.draw_code_line(
|
||||
&mut buffer,
|
||||
&mut row_num,
|
||||
highlight_parts,
|
||||
&highlight_parts,
|
||||
line_pos + line_start,
|
||||
line,
|
||||
show_code_change,
|
||||
|
|
@ -2176,7 +2176,7 @@ impl EmitterWriter {
|
|||
&self,
|
||||
buffer: &mut StyledBuffer,
|
||||
row_num: &mut usize,
|
||||
highlight_parts: &Vec<SubstitutionHighlight>,
|
||||
highlight_parts: &[SubstitutionHighlight],
|
||||
line_num: usize,
|
||||
line_to_add: &str,
|
||||
show_code_change: DisplaySuggestion,
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ impl CodeSuggestion {
|
|||
});
|
||||
buf.push_str(&part.snippet);
|
||||
let cur_hi = sm.lookup_char_pos(part.span.hi());
|
||||
if prev_hi.line == cur_lo.line && cur_hi.line == cur_lo.line {
|
||||
if cur_hi.line == cur_lo.line {
|
||||
// Account for the difference between the width of the current code and the
|
||||
// snippet being suggested, so that the *later* suggestions are correctly
|
||||
// aligned on the screen.
|
||||
|
|
|
|||
|
|
@ -133,3 +133,6 @@ expand_trace_macro = trace_macro
|
|||
expand_proc_macro_panicked =
|
||||
proc macro panicked
|
||||
.help = message: {$message}
|
||||
|
||||
expand_proc_macro_derive_tokens =
|
||||
proc-macro derive produced unparseable tokens
|
||||
|
|
|
|||
|
|
@ -390,3 +390,10 @@ pub(crate) struct ProcMacroPanicked {
|
|||
pub(crate) struct ProcMacroPanickedHelp {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(expand_proc_macro_derive_tokens)]
|
||||
pub struct ProcMacroDeriveTokens {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ pub(super) fn transcribe<'a>(
|
|||
}
|
||||
|
||||
// There should be no meta-var declarations in the invocation of a macro.
|
||||
mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"),
|
||||
mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ impl MultiItemModifier for DeriveProcMacro {
|
|||
|
||||
// fail if there have been errors emitted
|
||||
if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before {
|
||||
ecx.struct_span_err(span, "proc-macro derive produced unparseable tokens").emit();
|
||||
ecx.sess.emit_err(errors::ProcMacroDeriveTokens { span });
|
||||
}
|
||||
|
||||
ExpandResult::Ready(items)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ pub(crate) fn string_to_stream(source_str: String) -> TokenStream {
|
|||
ps.source_map().new_source_file(PathBuf::from("bogofile").into(), source_str),
|
||||
None,
|
||||
)
|
||||
.0
|
||||
}
|
||||
|
||||
/// Parses a string, returns a crate.
|
||||
|
|
|
|||
|
|
@ -90,6 +90,8 @@ declare_features! (
|
|||
(accepted, clone_closures, "1.26.0", Some(44490), None),
|
||||
/// Allows coercing non capturing closures to function pointers.
|
||||
(accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None),
|
||||
/// Allows using `cmpxchg16b` from `core::arch::x86_64`.
|
||||
(accepted, cmpxchg16b_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None),
|
||||
/// Allows usage of the `compile_error!` macro.
|
||||
(accepted, compile_error, "1.20.0", Some(40872), None),
|
||||
/// Allows `impl Trait` in function return types.
|
||||
|
|
|
|||
|
|
@ -256,7 +256,6 @@ declare_features! (
|
|||
(active, arm_target_feature, "1.27.0", Some(44839), None),
|
||||
(active, avx512_target_feature, "1.27.0", Some(44839), None),
|
||||
(active, bpf_target_feature, "1.54.0", Some(44839), None),
|
||||
(active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None),
|
||||
(active, ermsb_target_feature, "1.49.0", Some(44839), None),
|
||||
(active, hexagon_target_feature, "1.27.0", Some(44839), None),
|
||||
(active, mips_target_feature, "1.27.0", Some(44839), None),
|
||||
|
|
@ -317,8 +316,6 @@ declare_features! (
|
|||
(active, c_unwind, "1.52.0", Some(74990), None),
|
||||
/// Allows using C-variadics.
|
||||
(active, c_variadic, "1.34.0", Some(44930), None),
|
||||
/// Allows capturing disjoint fields in a closure/generator (RFC 2229).
|
||||
(incomplete, capture_disjoint_fields, "1.49.0", Some(53488), None),
|
||||
/// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
|
||||
(active, cfg_sanitize, "1.41.0", Some(39699), None),
|
||||
/// Allows `cfg(target_abi = "...")`.
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ declare_features! (
|
|||
(removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")),
|
||||
(removed, await_macro, "1.38.0", Some(50547), None,
|
||||
Some("subsumed by `.await` syntax")),
|
||||
/// Allows capturing disjoint fields in a closure/generator (RFC 2229).
|
||||
(removed, capture_disjoint_fields, "1.49.0", Some(53488), None, Some("stabilized in Rust 2021")),
|
||||
/// Allows comparing raw pointers during const eval.
|
||||
(removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
|
||||
Some("cannot be allowed in const eval in any meaningful way")),
|
||||
|
|
|
|||
|
|
@ -498,6 +498,7 @@ pub struct GenericParam<'hir> {
|
|||
pub pure_wrt_drop: bool,
|
||||
pub kind: GenericParamKind<'hir>,
|
||||
pub colon_span: Option<Span>,
|
||||
pub source: GenericParamSource,
|
||||
}
|
||||
|
||||
impl<'hir> GenericParam<'hir> {
|
||||
|
|
@ -516,6 +517,20 @@ impl<'hir> GenericParam<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Records where the generic parameter originated from.
|
||||
///
|
||||
/// This can either be from an item's generics, in which case it's typically
|
||||
/// early-bound (but can be a late-bound lifetime in functions, for example),
|
||||
/// or from a `for<...>` binder, in which case it's late-bound (and notably,
|
||||
/// does not show up in the parent item's generics).
|
||||
#[derive(Debug, HashStable_Generic, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum GenericParamSource {
|
||||
// Early or late-bound parameters defined on an item
|
||||
Generics,
|
||||
// Late-bound parameters defined via a `for<...>`
|
||||
Binder,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GenericParamCount {
|
||||
pub lifetimes: usize,
|
||||
|
|
|
|||
|
|
@ -62,14 +62,6 @@ hir_analysis_manual_implementation =
|
|||
|
||||
hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
|
||||
|
||||
hir_analysis_unused_extern_crate =
|
||||
unused extern crate
|
||||
.suggestion = remove it
|
||||
|
||||
hir_analysis_extern_crate_not_idiomatic =
|
||||
`extern crate` is not idiomatic in the new edition
|
||||
.suggestion = convert it to a `{$msg_code}`
|
||||
|
||||
hir_analysis_trait_object_declared_with_no_traits =
|
||||
at least one trait is required for an object type
|
||||
.alias_span = this alias does not contain a trait
|
||||
|
|
@ -155,3 +147,11 @@ hir_analysis_main_function_generic_parameters = `main` function is not allowed t
|
|||
|
||||
hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions}
|
||||
.label = C-variadic function must have a compatible calling convention
|
||||
|
||||
hir_analysis_cannot_capture_late_bound_ty_in_anon_const =
|
||||
cannot capture late-bound type parameter in a constant
|
||||
.label = parameter defined here
|
||||
|
||||
hir_analysis_cannot_capture_late_bound_const_in_anon_const =
|
||||
cannot capture late-bound const parameter in a constant
|
||||
.label = parameter defined here
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ use rustc_middle::middle::stability::AllowUnstable;
|
|||
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
|
||||
use rustc_middle::ty::DynKind;
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
use rustc_middle::ty::{self, Const, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::edition::Edition;
|
||||
|
|
@ -50,6 +50,7 @@ use rustc_trait_selection::traits::{self, astconv_object_safety_violations, Obli
|
|||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::Display;
|
||||
use std::slice;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -1095,11 +1096,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
// those that do.
|
||||
self.one_bound_for_assoc_type(
|
||||
|| traits::supertraits(tcx, trait_ref),
|
||||
|| trait_ref.print_only_trait_path().to_string(),
|
||||
trait_ref.print_only_trait_path(),
|
||||
binding.item_name,
|
||||
path_span,
|
||||
|| match binding.kind {
|
||||
ConvertedBindingKind::Equality(ty) => Some(ty.to_string()),
|
||||
match binding.kind {
|
||||
ConvertedBindingKind::Equality(term) => Some(term),
|
||||
_ => None,
|
||||
},
|
||||
)?
|
||||
|
|
@ -1789,10 +1790,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
assoc_name,
|
||||
)
|
||||
},
|
||||
|| param_name.to_string(),
|
||||
param_name,
|
||||
assoc_name,
|
||||
span,
|
||||
|| None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -1802,10 +1803,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
fn one_bound_for_assoc_type<I>(
|
||||
&self,
|
||||
all_candidates: impl Fn() -> I,
|
||||
ty_param_name: impl Fn() -> String,
|
||||
ty_param_name: impl Display,
|
||||
assoc_name: Ident,
|
||||
span: Span,
|
||||
is_equality: impl Fn() -> Option<String>,
|
||||
is_equality: Option<ty::Term<'tcx>>,
|
||||
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed>
|
||||
where
|
||||
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
|
|
@ -1821,7 +1822,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
(None, None) => {
|
||||
let reported = self.complain_about_assoc_type_not_found(
|
||||
all_candidates,
|
||||
&ty_param_name(),
|
||||
&ty_param_name.to_string(),
|
||||
assoc_name,
|
||||
span,
|
||||
);
|
||||
|
|
@ -1833,7 +1834,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
if let Some(bound2) = next_cand {
|
||||
debug!(?bound2);
|
||||
|
||||
let is_equality = is_equality();
|
||||
let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
|
||||
let mut err = if is_equality.is_some() {
|
||||
// More specific Error Index entry.
|
||||
|
|
@ -1843,7 +1843,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
E0222,
|
||||
"ambiguous associated type `{}` in bounds of `{}`",
|
||||
assoc_name,
|
||||
ty_param_name()
|
||||
ty_param_name
|
||||
)
|
||||
} else {
|
||||
struct_span_err!(
|
||||
|
|
@ -1852,7 +1852,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
E0221,
|
||||
"ambiguous associated type `{}` in bounds of `{}`",
|
||||
assoc_name,
|
||||
ty_param_name()
|
||||
ty_param_name
|
||||
)
|
||||
};
|
||||
err.span_label(span, format!("ambiguous associated type `{}`", assoc_name));
|
||||
|
|
@ -1886,18 +1886,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
err.span_suggestion_verbose(
|
||||
span.with_hi(assoc_name.span.lo()),
|
||||
"use fully qualified syntax to disambiguate",
|
||||
format!(
|
||||
"<{} as {}>::",
|
||||
ty_param_name(),
|
||||
bound.print_only_trait_path(),
|
||||
),
|
||||
format!("<{} as {}>::", ty_param_name, bound.print_only_trait_path()),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
err.note(&format!(
|
||||
"associated type `{}` could derive from `{}`",
|
||||
ty_param_name(),
|
||||
ty_param_name,
|
||||
bound.print_only_trait_path(),
|
||||
));
|
||||
}
|
||||
|
|
@ -1906,7 +1902,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
err.help(&format!(
|
||||
"consider introducing a new type parameter `T` and adding `where` constraints:\
|
||||
\n where\n T: {},\n{}",
|
||||
ty_param_name(),
|
||||
ty_param_name,
|
||||
where_bounds.join(",\n"),
|
||||
));
|
||||
}
|
||||
|
|
@ -2070,10 +2066,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
|
||||
self.one_bound_for_assoc_type(
|
||||
|| traits::supertraits(tcx, ty::Binder::dummy(trait_ref.subst_identity())),
|
||||
|| "Self".to_string(),
|
||||
kw::SelfUpper,
|
||||
assoc_ident,
|
||||
span,
|
||||
|| None,
|
||||
None,
|
||||
)?
|
||||
}
|
||||
(
|
||||
|
|
@ -2403,8 +2399,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
infcx
|
||||
.can_eq(
|
||||
ty::ParamEnv::empty(),
|
||||
tcx.erase_regions(impl_.self_ty()),
|
||||
tcx.erase_regions(qself_ty),
|
||||
impl_.self_ty(),
|
||||
// Must fold past escaping bound vars too,
|
||||
// since we have those at this point in astconv.
|
||||
tcx.fold_regions(qself_ty, |_, _| tcx.lifetimes.re_erased),
|
||||
)
|
||||
})
|
||||
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
|||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtDef, DefIdTree, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt,
|
||||
self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
|
||||
use rustc_span::symbol::sym;
|
||||
|
|
@ -792,8 +791,10 @@ fn check_impl_items_against_trait<'tcx>(
|
|||
trait_def.must_implement_one_of.as_deref();
|
||||
|
||||
for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
|
||||
let is_implemented = ancestors
|
||||
.leaf_def(tcx, trait_item_id)
|
||||
let leaf_def = ancestors.leaf_def(tcx, trait_item_id);
|
||||
|
||||
let is_implemented = leaf_def
|
||||
.as_ref()
|
||||
.map_or(false, |node_item| node_item.item.defaultness(tcx).has_value());
|
||||
|
||||
if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
|
||||
|
|
@ -801,8 +802,8 @@ fn check_impl_items_against_trait<'tcx>(
|
|||
}
|
||||
|
||||
// true if this item is specifically implemented in this impl
|
||||
let is_implemented_here = ancestors
|
||||
.leaf_def(tcx, trait_item_id)
|
||||
let is_implemented_here = leaf_def
|
||||
.as_ref()
|
||||
.map_or(false, |node_item| !node_item.defining_node.is_from_trait());
|
||||
|
||||
if !is_implemented_here {
|
||||
|
|
@ -831,6 +832,36 @@ fn check_impl_items_against_trait<'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(leaf_def) = &leaf_def
|
||||
&& !leaf_def.is_final()
|
||||
&& let def_id = leaf_def.item.def_id
|
||||
&& tcx.impl_method_has_trait_impl_trait_tys(def_id)
|
||||
{
|
||||
let def_kind = tcx.def_kind(def_id);
|
||||
let descr = tcx.def_kind_descr(def_kind, def_id);
|
||||
let (msg, feature) = if tcx.asyncness(def_id).is_async() {
|
||||
(
|
||||
format!("async {descr} in trait cannot be specialized"),
|
||||
sym::async_fn_in_trait,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
format!(
|
||||
"{descr} with return-position `impl Trait` in trait cannot be specialized"
|
||||
),
|
||||
sym::return_position_impl_trait_in_trait,
|
||||
)
|
||||
};
|
||||
tcx.sess
|
||||
.struct_span_err(tcx.def_span(def_id), msg)
|
||||
.note(format!(
|
||||
"specialization behaves in inconsistent and \
|
||||
surprising ways with `#![feature({feature})]`, \
|
||||
and for now is disallowed"
|
||||
))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
if !missing_items.is_empty() {
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ use rustc_infer::traits::util;
|
|||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::util::ExplicitSelf;
|
||||
use rustc_middle::ty::{
|
||||
self, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||
TypeVisitableExt,
|
||||
self, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
|
@ -648,6 +647,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
|
||||
)
|
||||
.fold_with(&mut collector);
|
||||
|
||||
debug_assert_ne!(
|
||||
collector.types.len(),
|
||||
0,
|
||||
"expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`"
|
||||
);
|
||||
|
||||
let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
|
||||
trait_sig.error_reported()?;
|
||||
let trait_return_ty = trait_sig.output();
|
||||
|
|
@ -1866,7 +1872,7 @@ pub(super) fn check_type_bounds<'tcx>(
|
|||
// type Bar<C> =...
|
||||
// }
|
||||
//
|
||||
// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>
|
||||
// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>`
|
||||
// - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
|
||||
// - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
|
||||
// the *trait* with the generic associated type parameters (as bound vars).
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
use crate::errors::{ExternCrateNotIdiomatic, UnusedExternCrate};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::lint;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
pub fn check_crate(tcx: TyCtxt<'_>) {
|
||||
let mut used_trait_imports: UnordSet<LocalDefId> = Default::default();
|
||||
|
|
@ -43,131 +39,4 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||
|lint| lint,
|
||||
);
|
||||
}
|
||||
|
||||
unused_crates_lint(tcx);
|
||||
}
|
||||
|
||||
fn unused_crates_lint(tcx: TyCtxt<'_>) {
|
||||
let lint = lint::builtin::UNUSED_EXTERN_CRATES;
|
||||
|
||||
// Collect first the crates that are completely unused. These we
|
||||
// can always suggest removing (no matter which edition we are
|
||||
// in).
|
||||
let unused_extern_crates: FxHashMap<LocalDefId, Span> = tcx
|
||||
.maybe_unused_extern_crates(())
|
||||
.iter()
|
||||
.filter(|&&(def_id, _)| {
|
||||
tcx.extern_mod_stmt_cnum(def_id).map_or(true, |cnum| {
|
||||
!tcx.is_compiler_builtins(cnum)
|
||||
&& !tcx.is_panic_runtime(cnum)
|
||||
&& !tcx.has_global_allocator(cnum)
|
||||
&& !tcx.has_panic_handler(cnum)
|
||||
})
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
// Collect all the extern crates (in a reliable order).
|
||||
let mut crates_to_lint = vec![];
|
||||
|
||||
for id in tcx.hir().items() {
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::ExternCrate) {
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::ExternCrate(orig_name) = item.kind {
|
||||
crates_to_lint.push(ExternCrateToLint {
|
||||
def_id: item.owner_id.to_def_id(),
|
||||
span: item.span,
|
||||
orig_name,
|
||||
warn_if_unused: !item.ident.as_str().starts_with('_'),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let extern_prelude = &tcx.resolutions(()).extern_prelude;
|
||||
|
||||
for extern_crate in &crates_to_lint {
|
||||
let def_id = extern_crate.def_id.expect_local();
|
||||
let item = tcx.hir().expect_item(def_id);
|
||||
|
||||
// If the crate is fully unused, we suggest removing it altogether.
|
||||
// We do this in any edition.
|
||||
if extern_crate.warn_if_unused {
|
||||
if let Some(&span) = unused_extern_crates.get(&def_id) {
|
||||
// Removal suggestion span needs to include attributes (Issue #54400)
|
||||
let id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let span_with_attrs = tcx
|
||||
.hir()
|
||||
.attrs(id)
|
||||
.iter()
|
||||
.map(|attr| attr.span)
|
||||
.fold(span, |acc, attr_span| acc.to(attr_span));
|
||||
|
||||
tcx.emit_spanned_lint(lint, id, span, UnusedExternCrate { span: span_with_attrs });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are not in Rust 2018 edition, then we don't make any further
|
||||
// suggestions.
|
||||
if !tcx.sess.rust_2018() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the extern crate isn't in the extern prelude,
|
||||
// there is no way it can be written as a `use`.
|
||||
let orig_name = extern_crate.orig_name.unwrap_or(item.ident.name);
|
||||
if !extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the extern crate is renamed, then we cannot suggest replacing it with a use as this
|
||||
// would not insert the new name into the prelude, where other imports in the crate may be
|
||||
// expecting it.
|
||||
if extern_crate.orig_name.is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
// If the extern crate has any attributes, they may have funky
|
||||
// semantics we can't faithfully represent using `use` (most
|
||||
// notably `#[macro_use]`). Ignore it.
|
||||
if !tcx.hir().attrs(id).is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let base_replacement = match extern_crate.orig_name {
|
||||
Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name),
|
||||
None => format!("use {};", item.ident.name),
|
||||
};
|
||||
let vis = tcx.sess.source_map().span_to_snippet(item.vis_span).unwrap_or_default();
|
||||
let add_vis = |to| if vis.is_empty() { to } else { format!("{} {}", vis, to) };
|
||||
tcx.emit_spanned_lint(
|
||||
lint,
|
||||
id,
|
||||
extern_crate.span,
|
||||
ExternCrateNotIdiomatic {
|
||||
span: extern_crate.span,
|
||||
msg_code: add_vis("use".to_string()),
|
||||
suggestion_code: add_vis(base_replacement),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct ExternCrateToLint {
|
||||
/// `DefId` of the extern crate
|
||||
def_id: DefId,
|
||||
|
||||
/// span from the item
|
||||
span: Span,
|
||||
|
||||
/// if `Some`, then this is renamed (`extern crate orig_name as
|
||||
/// crate_name`), and -- perhaps surprisingly -- this stores the
|
||||
/// *original* name (`item.name` will contain the new name)
|
||||
orig_name: Option<Symbol>,
|
||||
|
||||
/// if `false`, the original name started with `_`, so we shouldn't lint
|
||||
/// about it going unused (but we should still emit idiom lints).
|
||||
warn_if_unused: bool,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -437,7 +437,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
|
|||
}
|
||||
|
||||
// Here we are considering a case of converting
|
||||
// `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
|
||||
// `S<P0...Pn>` to `S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
|
||||
// which acts like a pointer to `U`, but carries along some extra data of type `T`:
|
||||
//
|
||||
// struct Foo<T, U> {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::astconv::AstConv;
|
|||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::util;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,15 @@ use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeNa
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::resolve_bound_vars::*;
|
||||
use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use std::fmt;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
trait RegionExt {
|
||||
fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
|
||||
|
||||
|
|
@ -161,6 +163,15 @@ enum Scope<'a> {
|
|||
s: ScopeRef<'a>,
|
||||
},
|
||||
|
||||
/// Disallows capturing non-lifetime binders from parent scopes.
|
||||
///
|
||||
/// This is necessary for something like `for<T> [(); { /* references T */ }]:`,
|
||||
/// since we don't do something more correct like replacing any captured
|
||||
/// late-bound vars with early-bound params in the const's own generics.
|
||||
AnonConstBoundary {
|
||||
s: ScopeRef<'a>,
|
||||
},
|
||||
|
||||
Root {
|
||||
opt_parent_item: Option<LocalDefId>,
|
||||
},
|
||||
|
|
@ -211,6 +222,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
|
|||
.field("s", &"..")
|
||||
.finish(),
|
||||
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
|
||||
Scope::AnonConstBoundary { s: _ } => f.debug_struct("AnonConstBoundary").finish(),
|
||||
Scope::Root { opt_parent_item } => {
|
||||
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
|
||||
}
|
||||
|
|
@ -312,7 +324,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
break (vec![], BinderScopeType::Normal);
|
||||
}
|
||||
|
||||
Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => {
|
||||
Scope::Elision { s, .. }
|
||||
| Scope::ObjectLifetimeDefault { s, .. }
|
||||
| Scope::AnonConstBoundary { s } => {
|
||||
scope = s;
|
||||
}
|
||||
|
||||
|
|
@ -1029,50 +1043,64 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) {
|
||||
self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow);
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
|
||||
self.with(Scope::AnonConstBoundary { s: self.scope }, |this| {
|
||||
intravisit::walk_anon_const(this, c);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault {
|
||||
debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam);
|
||||
let param_def_id = param_def_id.expect_local();
|
||||
let parent_def_id = tcx.local_parent(param_def_id);
|
||||
let generics = tcx.hir().get_generics(parent_def_id).unwrap();
|
||||
let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id);
|
||||
let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap();
|
||||
let hir::Node::GenericParam(param) = tcx.hir().get_by_def_id(param_def_id) else {
|
||||
bug!("expected GenericParam for object_lifetime_default");
|
||||
};
|
||||
match param.source {
|
||||
hir::GenericParamSource::Generics => {
|
||||
let parent_def_id = tcx.local_parent(param_def_id);
|
||||
let generics = tcx.hir().get_generics(parent_def_id).unwrap();
|
||||
let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id);
|
||||
let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap();
|
||||
|
||||
// Scan the bounds and where-clauses on parameters to extract bounds
|
||||
// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
|
||||
// for each type parameter.
|
||||
match param.kind {
|
||||
GenericParamKind::Type { .. } => {
|
||||
let mut set = Set1::Empty;
|
||||
// Scan the bounds and where-clauses on parameters to extract bounds
|
||||
// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
|
||||
// for each type parameter.
|
||||
match param.kind {
|
||||
GenericParamKind::Type { .. } => {
|
||||
let mut set = Set1::Empty;
|
||||
|
||||
// Look for `type: ...` where clauses.
|
||||
for bound in generics.bounds_for_param(param_def_id) {
|
||||
// Ignore `for<'a> type: ...` as they can change what
|
||||
// lifetimes mean (although we could "just" handle it).
|
||||
if !bound.bound_generic_params.is_empty() {
|
||||
continue;
|
||||
}
|
||||
// Look for `type: ...` where clauses.
|
||||
for bound in generics.bounds_for_param(param_def_id) {
|
||||
// Ignore `for<'a> type: ...` as they can change what
|
||||
// lifetimes mean (although we could "just" handle it).
|
||||
if !bound.bound_generic_params.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
for bound in bound.bounds {
|
||||
if let hir::GenericBound::Outlives(lifetime) = bound {
|
||||
set.insert(lifetime.res);
|
||||
for bound in bound.bounds {
|
||||
if let hir::GenericBound::Outlives(lifetime) = bound {
|
||||
set.insert(lifetime.res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match set {
|
||||
Set1::Empty => ObjectLifetimeDefault::Empty,
|
||||
Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
|
||||
Set1::One(hir::LifetimeName::Param(param_def_id)) => {
|
||||
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
|
||||
}
|
||||
_ => ObjectLifetimeDefault::Ambiguous,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match set {
|
||||
Set1::Empty => ObjectLifetimeDefault::Empty,
|
||||
Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
|
||||
Set1::One(hir::LifetimeName::Param(param_def_id)) => {
|
||||
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
|
||||
_ => {
|
||||
bug!("object_lifetime_default_raw must only be called on a type parameter")
|
||||
}
|
||||
_ => ObjectLifetimeDefault::Ambiguous,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
bug!("object_lifetime_default_raw must only be called on a type parameter")
|
||||
}
|
||||
hir::GenericParamSource::Binder => ObjectLifetimeDefault::Empty,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1267,7 +1295,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
Scope::Elision { s, .. }
|
||||
| Scope::ObjectLifetimeDefault { s, .. }
|
||||
| Scope::Supertrait { s, .. }
|
||||
| Scope::TraitRefBoundary { s, .. } => {
|
||||
| Scope::TraitRefBoundary { s, .. }
|
||||
| Scope::AnonConstBoundary { s } => {
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
|
|
@ -1332,7 +1361,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
| Scope::Elision { s, .. }
|
||||
| Scope::ObjectLifetimeDefault { s, .. }
|
||||
| Scope::Supertrait { s, .. }
|
||||
| Scope::TraitRefBoundary { s, .. } => {
|
||||
| Scope::TraitRefBoundary { s, .. }
|
||||
| Scope::AnonConstBoundary { s } => {
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
|
|
@ -1351,6 +1381,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
// search.
|
||||
let mut late_depth = 0;
|
||||
let mut scope = self.scope;
|
||||
let mut crossed_anon_const = false;
|
||||
let result = loop {
|
||||
match *scope {
|
||||
Scope::Body { s, .. } => {
|
||||
|
|
@ -1384,17 +1415,44 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
| Scope::TraitRefBoundary { s, .. } => {
|
||||
scope = s;
|
||||
}
|
||||
|
||||
Scope::AnonConstBoundary { s } => {
|
||||
crossed_anon_const = true;
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(def) = result {
|
||||
if let ResolvedArg::LateBound(..) = def && crossed_anon_const {
|
||||
let use_span = self.tcx.hir().span(hir_id);
|
||||
let def_span = self.tcx.def_span(param_def_id);
|
||||
match self.tcx.def_kind(param_def_id) {
|
||||
DefKind::ConstParam => {
|
||||
self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Const {
|
||||
use_span,
|
||||
def_span,
|
||||
});
|
||||
}
|
||||
DefKind::TyParam => {
|
||||
self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Type {
|
||||
use_span,
|
||||
def_span,
|
||||
});
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
self.map.defs.insert(hir_id, def);
|
||||
return;
|
||||
}
|
||||
|
||||
self.tcx
|
||||
.sess
|
||||
.delay_span_bug(self.tcx.hir().span(hir_id), "could not resolve {param_def_id:?}");
|
||||
self.tcx.sess.delay_span_bug(
|
||||
self.tcx.hir().span(hir_id),
|
||||
format!("could not resolve {param_def_id:?}"),
|
||||
);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
|
@ -1465,7 +1523,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
| Scope::Elision { s, .. }
|
||||
| Scope::ObjectLifetimeDefault { s, .. }
|
||||
| Scope::Supertrait { s, .. }
|
||||
| Scope::TraitRefBoundary { s, .. } => {
|
||||
| Scope::TraitRefBoundary { s, .. }
|
||||
| Scope::AnonConstBoundary { s } => {
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
|
|
@ -1701,7 +1760,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
|
||||
Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l,
|
||||
|
||||
Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => {
|
||||
Scope::Supertrait { s, .. }
|
||||
| Scope::TraitRefBoundary { s, .. }
|
||||
| Scope::AnonConstBoundary { s } => {
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_middle::ty::print::with_forced_trimmed_paths;
|
|||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{
|
||||
self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
self, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_errors::{
|
|||
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
|
||||
MultiSpan,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
|
||||
|
|
@ -247,26 +247,6 @@ pub struct SubstsOnOverriddenImpl {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_analysis_unused_extern_crate)]
|
||||
pub struct UnusedExternCrate {
|
||||
#[suggestion(applicability = "machine-applicable", code = "")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_analysis_extern_crate_not_idiomatic)]
|
||||
pub struct ExternCrateNotIdiomatic {
|
||||
#[suggestion(
|
||||
style = "short",
|
||||
applicability = "machine-applicable",
|
||||
code = "{suggestion_code}"
|
||||
)]
|
||||
pub span: Span,
|
||||
pub msg_code: String,
|
||||
pub suggestion_code: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_const_impl_for_non_const_trait)]
|
||||
pub struct ConstImplForNonConstTrait {
|
||||
|
|
@ -401,3 +381,21 @@ pub(crate) struct VariadicFunctionCompatibleConvention<'a> {
|
|||
pub span: Span,
|
||||
pub conventions: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum CannotCaptureLateBoundInAnonConst {
|
||||
#[diag(hir_analysis_cannot_capture_late_bound_ty_in_anon_const)]
|
||||
Type {
|
||||
#[primary_span]
|
||||
use_span: Span,
|
||||
#[label]
|
||||
def_span: Span,
|
||||
},
|
||||
#[diag(hir_analysis_cannot_capture_late_bound_const_in_anon_const)]
|
||||
Const {
|
||||
#[primary_span]
|
||||
use_span: Span,
|
||||
#[label]
|
||||
def_span: Span,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgKind};
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_hir::def::DefKind;
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{DefIdTree, TypeSuperVisitable, TypeVisitable};
|
||||
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
/// Defines the `TermsContext` basically houses an arena where we can
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
probe::ProbeScope::TraitsInScope,
|
||||
None,
|
||||
) {
|
||||
Ok(pick) => pick.self_ty,
|
||||
Ok(pick) => eraser.fold_ty(pick.self_ty),
|
||||
Err(_) => rcvr_ty,
|
||||
};
|
||||
// Remove one layer of references to account for `&mut self` and
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use rustc_middle::ty::error::TypeError;
|
|||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, Ty, TyCtxt, UserType,
|
||||
self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType,
|
||||
};
|
||||
use rustc_middle::ty::{GenericArgKind, SubstsRef, UserSelfTy, UserSubsts};
|
||||
use rustc_session::lint;
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::{
|
||||
self, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
|
||||
};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||
use rustc_span::{self, Span};
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
|
|
@ -714,12 +712,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.tcx.parent(expr_ctor_def_id)
|
||||
}
|
||||
hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, hir::def::CtorKind::Fn) => {
|
||||
// If this is a variant, its parent is the type definition.
|
||||
if in_ty_adt.did() != self.tcx.parent(expr_ctor_def_id) {
|
||||
// For a typical enum like
|
||||
// `enum Blah<T> { Variant(T) }`
|
||||
// we get the following resolutions:
|
||||
// - expr_ctor_def_id ::: DefId(0:29 ~ source_file[b442]::Blah::Variant::{constructor#0})
|
||||
// - self.tcx.parent(expr_ctor_def_id) ::: DefId(0:28 ~ source_file[b442]::Blah::Variant)
|
||||
// - self.tcx.parent(self.tcx.parent(expr_ctor_def_id)) ::: DefId(0:26 ~ source_file[b442]::Blah)
|
||||
|
||||
// Therefore, we need to go up once to obtain the variant and up twice to obtain the type.
|
||||
// Note that this pattern still holds even when we `use` a variant or `use` an enum type to rename it, or chain `use` expressions
|
||||
// together; this resolution is handled automatically by `qpath_res`.
|
||||
|
||||
// FIXME: Deal with type aliases?
|
||||
if in_ty_adt.did() == self.tcx.parent(self.tcx.parent(expr_ctor_def_id)) {
|
||||
// The constructor definition refers to the "constructor" of the variant:
|
||||
// For example, `Some(5)` triggers this case.
|
||||
self.tcx.parent(expr_ctor_def_id)
|
||||
} else {
|
||||
// FIXME: Deal with type aliases?
|
||||
return Err(expr);
|
||||
}
|
||||
expr_ctor_def_id
|
||||
}
|
||||
_ => {
|
||||
return Err(expr);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use rustc_infer::infer::InferOk;
|
|||
use rustc_infer::infer::TypeTrace;
|
||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
|
||||
use rustc_middle::ty::{self, IsSuggestable, Ty};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::{self, sym, Span};
|
||||
|
|
@ -36,7 +36,6 @@ use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}
|
|||
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
use std::slice;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(in super::super) fn check_casts(&mut self) {
|
||||
|
|
@ -1507,11 +1506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let coerce = if blk.targeted_by_break {
|
||||
CoerceMany::new(coerce_to_ty)
|
||||
} else {
|
||||
let tail_expr: &[&hir::Expr<'_>] = match tail_expr {
|
||||
Some(e) => slice::from_ref(e),
|
||||
None => &[],
|
||||
};
|
||||
CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr)
|
||||
CoerceMany::with_coercion_sites(coerce_to_ty, blk.expr.as_slice())
|
||||
};
|
||||
|
||||
let prev_diverges = self.diverges.get();
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_infer::traits::{self, StatementAsExpression};
|
|||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{
|
||||
self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty,
|
||||
self, suggest_constraining_type_params, Binder, IsSuggestable, ToPredicate, Ty,
|
||||
TypeVisitableExt,
|
||||
};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#![feature(min_specialization)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(option_as_slice)]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
|
|
|
|||
|
|
@ -636,7 +636,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
|||
// `&&Some(x,)` `place_foo`
|
||||
// `&Some(x,)` `deref { place_foo}`
|
||||
// `Some(x,)` `deref { deref { place_foo }}`
|
||||
// (x,)` `field0 { deref { deref { place_foo }}}` <- resulting place
|
||||
// `(x,)` `field0 { deref { deref { place_foo }}}` <- resulting place
|
||||
//
|
||||
// The above example has no adjustments. If the code were instead the (after adjustments,
|
||||
// equivalent) version
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use rustc_middle::traits::util::supertraits;
|
|||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
|
||||
use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
|
||||
use rustc_middle::ty::{self, DefIdTree, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Symbol;
|
||||
|
|
@ -333,6 +333,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
rcvr_ty.prefix_string(self.tcx),
|
||||
ty_str_reported,
|
||||
);
|
||||
if tcx.sess.source_map().is_multiline(sugg_span) {
|
||||
err.span_label(sugg_span.with_hi(span.lo()), "");
|
||||
}
|
||||
let ty_str = if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
|
||||
short_ty_str
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_middle::ty::adjustment::{
|
|||
};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{
|
||||
self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
self, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
use rustc_span::source_map::Spanned;
|
||||
|
|
@ -749,14 +749,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let opname = Ident::with_dummy_span(opname);
|
||||
let input_types =
|
||||
opt_rhs.as_ref().map(|(_, ty)| std::slice::from_ref(ty)).unwrap_or_default();
|
||||
let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip();
|
||||
let input_types = opt_rhs_ty.as_slice();
|
||||
let cause = self.cause(
|
||||
span,
|
||||
traits::BinOp {
|
||||
rhs_span: opt_rhs.map(|(expr, _)| expr.span),
|
||||
is_lit: opt_rhs
|
||||
.map_or(false, |(expr, _)| matches!(expr.kind, hir::ExprKind::Lit(_))),
|
||||
rhs_span: opt_rhs_expr.map(|expr| expr.span),
|
||||
is_lit: opt_rhs_expr
|
||||
.map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
|
||||
output_ty: expected.only_has_type(self),
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili
|
|||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use std::slice;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already.
|
||||
|
|
@ -393,11 +392,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Some(self.typeck_results.borrow().node_substs(expr.hir_id).type_at(1))
|
||||
}
|
||||
};
|
||||
let arg_tys = match arg_ty {
|
||||
None => &[],
|
||||
Some(ref ty) => slice::from_ref(ty),
|
||||
};
|
||||
|
||||
let arg_tys = arg_ty.as_slice();
|
||||
let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op);
|
||||
let method = match method {
|
||||
Some(ok) => self.register_infer_ok_obligations(ok),
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// We now fake capture information for all variables that are mentioned within the closure
|
||||
// We do this after handling migrations so that min_captures computes before
|
||||
if !enable_precise_capture(self.tcx, span) {
|
||||
if !enable_precise_capture(span) {
|
||||
let mut capture_information: InferredCaptureInformation<'tcx> = Default::default();
|
||||
|
||||
if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
|
||||
|
|
@ -265,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// If we have an origin, store it.
|
||||
if let Some(origin) = origin {
|
||||
let origin = if enable_precise_capture(self.tcx, span) {
|
||||
let origin = if enable_precise_capture(span) {
|
||||
(origin.0, origin.1)
|
||||
} else {
|
||||
(origin.0, Place { projections: vec![], ..origin.1 })
|
||||
|
|
@ -526,10 +526,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
|
||||
base => bug!("Expected upvar, found={:?}", base),
|
||||
};
|
||||
let var_ident = self.tcx.hir().ident(var_hir_id);
|
||||
|
||||
let Some(min_cap_list) = root_var_min_capture_list.get_mut(&var_hir_id) else {
|
||||
let mutability = self.determine_capture_mutability(&typeck_results, &place);
|
||||
let min_cap_list = vec![ty::CapturedPlace {
|
||||
var_ident,
|
||||
place,
|
||||
info: capture_info,
|
||||
mutability,
|
||||
|
|
@ -628,6 +630,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if !ancestor_found {
|
||||
let mutability = self.determine_capture_mutability(&typeck_results, &place);
|
||||
let captured_place = ty::CapturedPlace {
|
||||
var_ident,
|
||||
place,
|
||||
info: updated_capture_info,
|
||||
mutability,
|
||||
|
|
@ -1240,8 +1243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
///
|
||||
/// This will make more sense with an example:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(capture_disjoint_fields)]
|
||||
/// ```rust,edition2021
|
||||
///
|
||||
/// struct FancyInteger(i32); // This implements Drop
|
||||
///
|
||||
|
|
@ -2221,7 +2223,7 @@ fn determine_place_ancestry_relation<'tcx>(
|
|||
/// || drop(&*m.a.field_of_a)
|
||||
/// // Here we really do want to capture `*m.a` because that outlives `'static`
|
||||
///
|
||||
/// // If we capture `m`, then the closure no longer outlives `'static'
|
||||
/// // If we capture `m`, then the closure no longer outlives `'static`
|
||||
/// // it is constrained to `'a`
|
||||
/// }
|
||||
/// ```
|
||||
|
|
@ -2247,12 +2249,10 @@ fn truncate_capture_for_optimization(
|
|||
(place, curr_mode)
|
||||
}
|
||||
|
||||
/// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if
|
||||
/// user is using Rust Edition 2021 or higher.
|
||||
///
|
||||
/// Precise capture is enabled if user is using Rust Edition 2021 or higher.
|
||||
/// `span` is the span of the closure.
|
||||
fn enable_precise_capture(tcx: TyCtxt<'_>, span: Span) -> bool {
|
||||
fn enable_precise_capture(span: Span) -> bool {
|
||||
// We use span here to ensure that if the closure was generated by a macro with a different
|
||||
// edition.
|
||||
tcx.features().capture_disjoint_fields || span.rust_2021()
|
||||
span.rust_2021()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
//! the HIR doesn't change as a result of the annotations, which might
|
||||
//! perturb the reuse results.
|
||||
//!
|
||||
//! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")]
|
||||
//! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")]`
|
||||
//! allows for doing a more fine-grained check to see if pre- or post-lto data
|
||||
//! was re-used.
|
||||
|
||||
|
|
|
|||
|
|
@ -1870,7 +1870,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Subtracts `set from `row`. `set` can be either `BitSet` or
|
||||
/// Subtracts `set` from `row`. `set` can be either `BitSet` or
|
||||
/// `HybridBitSet`. Has no effect if `row` does not exist.
|
||||
///
|
||||
/// Returns true if the row was changed.
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ infer_subtype = ...so that the {$requirement ->
|
|||
[if_else_different] `if` and `else` have incompatible types
|
||||
[no_else] `if` missing an `else` returns `()`
|
||||
[fn_main_correct_type] `main` function has the correct type
|
||||
[fn_start_correct_type] #[start]` function has the correct type
|
||||
[fn_start_correct_type] `#[start]` function has the correct type
|
||||
[intristic_correct_type] intrinsic has the correct type
|
||||
[method_correct_type] method receiver has the correct type
|
||||
*[other] types are compatible
|
||||
|
|
@ -92,7 +92,7 @@ infer_subtype_2 = ...so that {$requirement ->
|
|||
[if_else_different] `if` and `else` have incompatible types
|
||||
[no_else] `if` missing an `else` returns `()`
|
||||
[fn_main_correct_type] `main` function has the correct type
|
||||
[fn_start_correct_type] #[start]` function has the correct type
|
||||
[fn_start_correct_type] `#[start]` function has the correct type
|
||||
[intristic_correct_type] intrinsic has the correct type
|
||||
[method_correct_type] method receiver has the correct type
|
||||
*[other] types are compatible
|
||||
|
|
@ -277,7 +277,7 @@ infer_tid_consider_borrowing = consider borrowing this type parameter in the tra
|
|||
infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
|
||||
infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
|
||||
infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s 'static` requirement
|
||||
infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement
|
||||
infer_dtcs_has_req_note = the used `impl` has a `'static` requirement
|
||||
infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement
|
||||
|
||||
|
|
@ -313,7 +313,7 @@ infer_but_needs_to_satisfy = {$has_param_name ->
|
|||
[false] ...and is required to live as long as `'static` here
|
||||
}
|
||||
.used_here = ...is used here...
|
||||
.introduced_by_bound = 'static` lifetime requirement introduced by this bound
|
||||
.introduced_by_bound = `'static` lifetime requirement introduced by this bound
|
||||
|
||||
infer_more_targeted = {$has_param_name ->
|
||||
[true] `{$param_name}`
|
||||
|
|
@ -345,3 +345,6 @@ infer_prlf_defined_without_sub = the lifetime defined here...
|
|||
infer_prlf_must_oultive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here
|
||||
infer_prlf_must_oultive_without_sup = ...must outlive the lifetime defined here
|
||||
infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
|
||||
|
||||
infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
|
||||
.label = opaque type defined here
|
||||
|
|
|
|||
|
|
@ -1147,3 +1147,13 @@ pub enum PlaceholderRelationLfNotSatisfied {
|
|||
note: (),
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(infer_opaque_captures_lifetime, code = "E0700")]
|
||||
pub struct OpaqueCapturesLifetime<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub opaque_ty_span: Span,
|
||||
pub opaque_ty: Ty<'tcx>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -369,6 +369,34 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
|
||||
fn to_trace(
|
||||
_: TyCtxt<'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
a_is_expected: bool,
|
||||
a: Self,
|
||||
b: Self,
|
||||
) -> TypeTrace<'tcx> {
|
||||
use GenericArgKind::*;
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: match (a.unpack(), b.unpack()) {
|
||||
(Lifetime(a), Lifetime(b)) => Regions(ExpectedFound::new(a_is_expected, a, b)),
|
||||
(Type(a), Type(b)) => Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
(Const(a), Const(b)) => {
|
||||
Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
|
||||
}
|
||||
|
||||
(Lifetime(_), Type(_) | Const(_))
|
||||
| (Type(_), Lifetime(_) | Const(_))
|
||||
| (Const(_), Lifetime(_) | Type(_)) => {
|
||||
bug!("relating different kinds: {a:?} {b:?}")
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
|
||||
fn to_trace(
|
||||
_: TyCtxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
|
||||
/// Like [Self::canonicalize_query], but preserves distinct universes. For
|
||||
/// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and
|
||||
/// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1`
|
||||
/// `'?1` is in `U3` would be canonicalized to have `?0` in `U1` and `'?1`
|
||||
/// in `U2`.
|
||||
///
|
||||
/// This is used for Chalk integration.
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use rustc_middle::ty::{self, List, TyCtxt};
|
|||
use rustc_span::source_map::Span;
|
||||
|
||||
pub use rustc_middle::infer::canonical::*;
|
||||
use substitute::CanonicalExt;
|
||||
pub use substitute::CanonicalExt;
|
||||
|
||||
mod canonicalizer;
|
||||
pub mod query_response;
|
||||
|
|
@ -100,7 +100,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
/// variable for it. If this is an existentially quantified
|
||||
/// variable, then you'll get a new inference variable; if it is a
|
||||
/// universally quantified variable, you get a placeholder.
|
||||
fn instantiate_canonical_var(
|
||||
///
|
||||
/// FIXME(-Ztrait-solver=next): This is public because it's used by the
|
||||
/// new trait solver which has a different canonicalization routine.
|
||||
/// We should somehow deduplicate all of this.
|
||||
pub fn instantiate_canonical_var(
|
||||
&self,
|
||||
span: Span,
|
||||
cv_info: CanonicalVarInfo<'tcx>,
|
||||
|
|
|
|||
|
|
@ -151,11 +151,21 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// FIXME: This method should only be used for canonical queries and therefore be private.
|
||||
///
|
||||
/// As the new solver does canonicalization slightly differently, this is also used there
|
||||
/// for now. This should hopefully change fairly soon.
|
||||
pub fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
|
||||
/// Used by the new solver as that one takes the opaque types at the end of a probe
|
||||
/// to deal with multiple candidates without having to recompute them.
|
||||
pub fn clone_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
|
||||
self.inner
|
||||
.borrow()
|
||||
.opaque_type_storage
|
||||
.opaque_types
|
||||
.iter()
|
||||
.map(|&(k, ref v)| {
|
||||
(self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
|
||||
std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
|
||||
.into_iter()
|
||||
.map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty))
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable};
|
|||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
|
||||
pub(super) trait CanonicalExt<'tcx, V> {
|
||||
/// FIXME(-Ztrait-solver=next): This or public because it is shared with the
|
||||
/// new trait solver implementation. We should deduplicate canonicalization.
|
||||
pub trait CanonicalExt<'tcx, V> {
|
||||
/// Instantiate the wrapped value, replacing each canonical value
|
||||
/// with the value given in `var_values`.
|
||||
fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ use super::lexical_region_resolve::RegionResolutionError;
|
|||
use super::region_constraints::GenericKind;
|
||||
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
||||
|
||||
use crate::errors;
|
||||
use crate::infer;
|
||||
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
|
||||
use crate::infer::ExpectedFound;
|
||||
|
|
@ -281,15 +282,13 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
|
|||
span: Span,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
hidden_region: ty::Region<'tcx>,
|
||||
opaque_ty: ty::OpaqueTypeKey<'tcx>,
|
||||
opaque_ty_key: ty::OpaqueTypeKey<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let opaque_ty = tcx.mk_opaque(opaque_ty.def_id.to_def_id(), opaque_ty.substs);
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
let mut err = tcx.sess.create_err(errors::OpaqueCapturesLifetime {
|
||||
span,
|
||||
E0700,
|
||||
"hidden type for `{opaque_ty}` captures lifetime that does not appear in bounds",
|
||||
);
|
||||
opaque_ty: tcx.mk_opaque(opaque_ty_key.def_id.to_def_id(), opaque_ty_key.substs),
|
||||
opaque_ty_span: tcx.def_span(opaque_ty_key.def_id),
|
||||
});
|
||||
|
||||
// Explain the region we are capturing.
|
||||
match *hidden_region {
|
||||
|
|
@ -1690,7 +1689,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
format!("{name} is defined in the current crate")
|
||||
} else {
|
||||
let crate_name = self.tcx.crate_name(defid.krate);
|
||||
format!("{name} is defined in crate `{crate_name}")
|
||||
format!("{name} is defined in crate `{crate_name}`")
|
||||
};
|
||||
diagnostic.span_note(def_span, msg);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use rustc_middle::hir::nested_filter;
|
|||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
|
||||
use rustc_middle::ty::{self, DefIdTree, InferConst};
|
||||
use rustc_middle::ty::{self, InferConst};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue