Auto merge of #100740 - Dylan-DPC:rollup-0td6yq4, r=Dylan-DPC
Rollup of 9 pull requests Successful merges: - #99576 (Do not allow `Drop` impl on foreign fundamental types) - #100081 (never consider unsafe blocks unused if they would be required with deny(unsafe_op_in_unsafe_fn)) - #100208 (make NOP dyn casts not require anything about the vtable) - #100494 (Cleanup rustdoc themes) - #100522 (Only check the `DefId` for the recursion check in MIR inliner.) - #100592 (Manually implement Debug for ImportKind.) - #100598 (Don't fix builtin index when Where clause is found) - #100721 (Add diagnostics lints to `rustc_type_ir` module) - #100731 (rustdoc: count deref and non-deref as same set of used methods) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e1b28cd2f1
48 changed files with 851 additions and 992 deletions
|
@ -29,6 +29,7 @@ pub(crate) fn unsized_info<'tcx>(
|
|||
let old_info =
|
||||
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
|
||||
if data_a.principal_def_id() == data_b.principal_def_id() {
|
||||
// A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables.
|
||||
return old_info;
|
||||
}
|
||||
|
||||
|
|
|
@ -151,6 +151,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
let old_info =
|
||||
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
|
||||
if data_a.principal_def_id() == data_b.principal_def_id() {
|
||||
// A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables.
|
||||
return old_info;
|
||||
}
|
||||
|
||||
|
|
|
@ -298,7 +298,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
self.write_immediate(val, dest)
|
||||
}
|
||||
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
|
||||
let (old_data, old_vptr) = self.read_immediate(src)?.to_scalar_pair()?;
|
||||
let val = self.read_immediate(src)?;
|
||||
if data_a.principal() == data_b.principal() {
|
||||
// A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables.
|
||||
return self.write_immediate(*val, dest);
|
||||
}
|
||||
let (old_data, old_vptr) = val.to_scalar_pair()?;
|
||||
let old_vptr = old_vptr.to_pointer(self)?;
|
||||
let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?;
|
||||
if old_trait != data_a.principal() {
|
||||
|
|
|
@ -24,8 +24,8 @@ typeck_lifetimes_or_bounds_mismatch_on_trait =
|
|||
.generics_label = lifetimes in impl do not match this {$item_kind} in trait
|
||||
|
||||
typeck_drop_impl_on_wrong_item =
|
||||
the `Drop` trait may only be implemented for structs, enums, and unions
|
||||
.label = must be a struct, enum, or union
|
||||
the `Drop` trait may only be implemented for local structs, enums, and unions
|
||||
.label = must be a struct, enum, or union in the current crate
|
||||
|
||||
typeck_field_already_declared =
|
||||
field `{$field_name}` is already declared
|
||||
|
|
|
@ -566,7 +566,7 @@ impl Drop for DiagnosticBuilderInner<'_> {
|
|||
),
|
||||
));
|
||||
handler.emit_diagnostic(&mut self.diagnostic);
|
||||
panic!();
|
||||
panic!("error was constructed but not emitted");
|
||||
}
|
||||
}
|
||||
// `.emit()` was previously called, or maybe we're during `.cancel()`.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use crate::mir::{Body, ConstantKind, Promoted};
|
||||
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
|
@ -115,21 +115,6 @@ pub enum UnusedUnsafe {
|
|||
/// `unsafe` block nested under another (used) `unsafe` block
|
||||
/// > ``… because it's nested under this `unsafe` block``
|
||||
InUnsafeBlock(hir::HirId),
|
||||
/// `unsafe` block nested under `unsafe fn`
|
||||
/// > ``… because it's nested under this `unsafe fn` ``
|
||||
///
|
||||
/// the second HirId here indicates the first usage of the `unsafe` block,
|
||||
/// which allows retrieval of the LintLevelSource for why that operation would
|
||||
/// have been permitted without the block
|
||||
InUnsafeFn(hir::HirId, hir::HirId),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
|
||||
pub enum UsedUnsafeBlockData {
|
||||
SomeDisallowedInUnsafeFn,
|
||||
// the HirId here indicates the first usage of the `unsafe` block
|
||||
// (i.e. the one that's first encountered in the MIR traversal of the unsafety check)
|
||||
AllAllowedInUnsafeFn(hir::HirId),
|
||||
}
|
||||
|
||||
#[derive(TyEncodable, TyDecodable, HashStable, Debug)]
|
||||
|
@ -138,10 +123,7 @@ pub struct UnsafetyCheckResult {
|
|||
pub violations: Vec<UnsafetyViolation>,
|
||||
|
||||
/// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
|
||||
///
|
||||
/// The keys are the used `unsafe` blocks, the UnusedUnsafeKind indicates whether
|
||||
/// or not any of the usages happen at a place that doesn't allow `unsafe_op_in_unsafe_fn`.
|
||||
pub used_unsafe_blocks: FxHashMap<hir::HirId, UsedUnsafeBlockData>,
|
||||
pub used_unsafe_blocks: FxHashSet<hir::HirId>,
|
||||
|
||||
/// This is `Some` iff the item is not a closure.
|
||||
pub unused_unsafes: Option<Vec<(hir::HirId, UnusedUnsafe)>>,
|
||||
|
|
|
@ -75,10 +75,11 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
|||
match self.safety_context {
|
||||
SafetyContext::BuiltinUnsafeBlock => {}
|
||||
SafetyContext::UnsafeBlock { ref mut used, .. } => {
|
||||
if !self.body_unsafety.is_unsafe() || !unsafe_op_in_unsafe_fn_allowed {
|
||||
// Mark this block as useful
|
||||
*used = true;
|
||||
}
|
||||
// Mark this block as useful (even inside `unsafe fn`, where it is technically
|
||||
// redundant -- but we want to eventually enable `unsafe_op_in_unsafe_fn` by
|
||||
// default which will require those blocks:
|
||||
// https://github.com/rust-lang/rust/issues/71668#issuecomment-1203075594).
|
||||
*used = true;
|
||||
}
|
||||
SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
|
||||
SafetyContext::UnsafeFn => {
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::hir_id::HirId;
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::{lint, mir::*};
|
||||
use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
|
||||
use rustc_session::lint::Level;
|
||||
|
||||
use std::collections::hash_map;
|
||||
use std::ops::Bound;
|
||||
|
||||
pub struct UnsafetyChecker<'a, 'tcx> {
|
||||
|
@ -23,10 +22,7 @@ pub struct UnsafetyChecker<'a, 'tcx> {
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
||||
/// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
|
||||
///
|
||||
/// The keys are the used `unsafe` blocks, the UnusedUnsafeKind indicates whether
|
||||
/// or not any of the usages happen at a place that doesn't allow `unsafe_op_in_unsafe_fn`.
|
||||
used_unsafe_blocks: FxHashMap<HirId, UsedUnsafeBlockData>,
|
||||
used_unsafe_blocks: FxHashSet<HirId>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
||||
|
@ -130,10 +126,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
|||
&AggregateKind::Closure(def_id, _) | &AggregateKind::Generator(def_id, _, _) => {
|
||||
let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
|
||||
self.tcx.unsafety_check_result(def_id);
|
||||
self.register_violations(
|
||||
violations,
|
||||
used_unsafe_blocks.iter().map(|(&h, &d)| (h, d)),
|
||||
);
|
||||
self.register_violations(violations, used_unsafe_blocks.iter().copied());
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
|
@ -257,22 +250,8 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
|
|||
fn register_violations<'a>(
|
||||
&mut self,
|
||||
violations: impl IntoIterator<Item = &'a UnsafetyViolation>,
|
||||
new_used_unsafe_blocks: impl IntoIterator<Item = (HirId, UsedUnsafeBlockData)>,
|
||||
new_used_unsafe_blocks: impl IntoIterator<Item = HirId>,
|
||||
) {
|
||||
use UsedUnsafeBlockData::{AllAllowedInUnsafeFn, SomeDisallowedInUnsafeFn};
|
||||
|
||||
let update_entry = |this: &mut Self, hir_id, new_usage| {
|
||||
match this.used_unsafe_blocks.entry(hir_id) {
|
||||
hash_map::Entry::Occupied(mut entry) => {
|
||||
if new_usage == SomeDisallowedInUnsafeFn {
|
||||
*entry.get_mut() = SomeDisallowedInUnsafeFn;
|
||||
}
|
||||
}
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
entry.insert(new_usage);
|
||||
}
|
||||
};
|
||||
};
|
||||
let safety = self.body.source_scopes[self.source_info.scope]
|
||||
.local_data
|
||||
.as_ref()
|
||||
|
@ -299,22 +278,14 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
|
|||
}
|
||||
}),
|
||||
Safety::BuiltinUnsafe => {}
|
||||
Safety::ExplicitUnsafe(hir_id) => violations.into_iter().for_each(|violation| {
|
||||
update_entry(
|
||||
self,
|
||||
hir_id,
|
||||
match self.tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, violation.lint_root).0
|
||||
{
|
||||
Level::Allow => AllAllowedInUnsafeFn(violation.lint_root),
|
||||
_ => SomeDisallowedInUnsafeFn,
|
||||
},
|
||||
)
|
||||
Safety::ExplicitUnsafe(hir_id) => violations.into_iter().for_each(|_violation| {
|
||||
self.used_unsafe_blocks.insert(hir_id);
|
||||
}),
|
||||
};
|
||||
|
||||
new_used_unsafe_blocks
|
||||
.into_iter()
|
||||
.for_each(|(hir_id, usage_data)| update_entry(self, hir_id, usage_data));
|
||||
new_used_unsafe_blocks.into_iter().for_each(|hir_id| {
|
||||
self.used_unsafe_blocks.insert(hir_id);
|
||||
});
|
||||
}
|
||||
fn check_mut_borrowing_layout_constrained_field(
|
||||
&mut self,
|
||||
|
@ -411,34 +382,28 @@ enum Context {
|
|||
|
||||
struct UnusedUnsafeVisitor<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
used_unsafe_blocks: &'a FxHashMap<HirId, UsedUnsafeBlockData>,
|
||||
used_unsafe_blocks: &'a FxHashSet<HirId>,
|
||||
context: Context,
|
||||
unused_unsafes: &'a mut Vec<(HirId, UnusedUnsafe)>,
|
||||
}
|
||||
|
||||
impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> {
|
||||
fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
|
||||
use UsedUnsafeBlockData::{AllAllowedInUnsafeFn, SomeDisallowedInUnsafeFn};
|
||||
|
||||
if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules {
|
||||
let used = match self.tcx.lint_level_at_node(UNUSED_UNSAFE, block.hir_id) {
|
||||
(Level::Allow, _) => Some(SomeDisallowedInUnsafeFn),
|
||||
_ => self.used_unsafe_blocks.get(&block.hir_id).copied(),
|
||||
(Level::Allow, _) => true,
|
||||
_ => self.used_unsafe_blocks.contains(&block.hir_id),
|
||||
};
|
||||
let unused_unsafe = match (self.context, used) {
|
||||
(_, None) => UnusedUnsafe::Unused,
|
||||
(Context::Safe, Some(_))
|
||||
| (Context::UnsafeFn(_), Some(SomeDisallowedInUnsafeFn)) => {
|
||||
(_, false) => UnusedUnsafe::Unused,
|
||||
(Context::Safe, true) | (Context::UnsafeFn(_), true) => {
|
||||
let previous_context = self.context;
|
||||
self.context = Context::UnsafeBlock(block.hir_id);
|
||||
intravisit::walk_block(self, block);
|
||||
self.context = previous_context;
|
||||
return;
|
||||
}
|
||||
(Context::UnsafeFn(hir_id), Some(AllAllowedInUnsafeFn(lint_root))) => {
|
||||
UnusedUnsafe::InUnsafeFn(hir_id, lint_root)
|
||||
}
|
||||
(Context::UnsafeBlock(hir_id), Some(_)) => UnusedUnsafe::InUnsafeBlock(hir_id),
|
||||
(Context::UnsafeBlock(hir_id), true) => UnusedUnsafe::InUnsafeBlock(hir_id),
|
||||
};
|
||||
self.unused_unsafes.push((block.hir_id, unused_unsafe));
|
||||
}
|
||||
|
@ -462,7 +427,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> {
|
|||
fn check_unused_unsafe(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: LocalDefId,
|
||||
used_unsafe_blocks: &FxHashMap<HirId, UsedUnsafeBlockData>,
|
||||
used_unsafe_blocks: &FxHashSet<HirId>,
|
||||
) -> Vec<(HirId, UnusedUnsafe)> {
|
||||
let body_id = tcx.hir().maybe_body_owned_by(def_id);
|
||||
|
||||
|
@ -535,25 +500,6 @@ fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
|
|||
"because it's nested under this `unsafe` block",
|
||||
);
|
||||
}
|
||||
UnusedUnsafe::InUnsafeFn(id, usage_lint_root) => {
|
||||
db.span_label(
|
||||
tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
|
||||
"because it's nested under this `unsafe` fn",
|
||||
)
|
||||
.note(
|
||||
"this `unsafe` block does contain unsafe operations, \
|
||||
but those are already allowed in an `unsafe fn`",
|
||||
);
|
||||
let (level, source) =
|
||||
tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, usage_lint_root);
|
||||
assert_eq!(level, Level::Allow);
|
||||
lint::explain_lint_level_source(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
Level::Allow,
|
||||
source,
|
||||
&mut db,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
db.emit();
|
||||
|
|
|
@ -10,6 +10,7 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
|
@ -103,8 +104,12 @@ struct Inliner<'tcx> {
|
|||
param_env: ParamEnv<'tcx>,
|
||||
/// Caller codegen attributes.
|
||||
codegen_fn_attrs: &'tcx CodegenFnAttrs,
|
||||
/// Stack of inlined Instances.
|
||||
history: Vec<ty::Instance<'tcx>>,
|
||||
/// Stack of inlined instances.
|
||||
/// We only check the `DefId` and not the substs because we want to
|
||||
/// avoid inlining cases of polymorphic recursion.
|
||||
/// The number of `DefId`s is finite, so checking history is enough
|
||||
/// to ensure that we do not loop endlessly while inlining.
|
||||
history: Vec<DefId>,
|
||||
/// Indicates that the caller body has been modified.
|
||||
changed: bool,
|
||||
}
|
||||
|
@ -132,7 +137,7 @@ impl<'tcx> Inliner<'tcx> {
|
|||
Ok(new_blocks) => {
|
||||
debug!("inlined {}", callsite.callee);
|
||||
self.changed = true;
|
||||
self.history.push(callsite.callee);
|
||||
self.history.push(callsite.callee.def_id());
|
||||
self.process_blocks(caller_body, new_blocks);
|
||||
self.history.pop();
|
||||
}
|
||||
|
@ -308,7 +313,7 @@ impl<'tcx> Inliner<'tcx> {
|
|||
return None;
|
||||
}
|
||||
|
||||
if self.history.contains(&callee) {
|
||||
if self.history.contains(&callee.def_id()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ use std::{mem, ptr};
|
|||
type Res = def::Res<NodeId>;
|
||||
|
||||
/// Contains data for specific kinds of imports.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub enum ImportKind<'a> {
|
||||
Single {
|
||||
/// `source` in `use prefix::source as target`.
|
||||
|
@ -62,6 +62,44 @@ pub enum ImportKind<'a> {
|
|||
MacroUse,
|
||||
}
|
||||
|
||||
/// Manually implement `Debug` for `ImportKind` because the `source/target_bindings`
|
||||
/// contain `Cell`s which can introduce infinite loops while printing.
|
||||
impl<'a> std::fmt::Debug for ImportKind<'a> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use ImportKind::*;
|
||||
match self {
|
||||
Single {
|
||||
ref source,
|
||||
ref target,
|
||||
ref type_ns_only,
|
||||
ref nested,
|
||||
ref additional_ids,
|
||||
// Ignore the following to avoid an infinite loop while printing.
|
||||
source_bindings: _,
|
||||
target_bindings: _,
|
||||
} => f
|
||||
.debug_struct("Single")
|
||||
.field("source", source)
|
||||
.field("target", target)
|
||||
.field("type_ns_only", type_ns_only)
|
||||
.field("nested", nested)
|
||||
.field("additional_ids", additional_ids)
|
||||
.finish_non_exhaustive(),
|
||||
Glob { ref is_prelude, ref max_vis } => f
|
||||
.debug_struct("Glob")
|
||||
.field("is_prelude", is_prelude)
|
||||
.field("max_vis", max_vis)
|
||||
.finish(),
|
||||
ExternCrate { ref source, ref target } => f
|
||||
.debug_struct("ExternCrate")
|
||||
.field("source", source)
|
||||
.field("target", target)
|
||||
.finish(),
|
||||
MacroUse => f.debug_struct("MacroUse").finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// One import.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Import<'a> {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#![feature(fmt_helpers_for_derive)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// substitutions.
|
||||
|
||||
use crate::check::FnCtxt;
|
||||
|
||||
use hir::def_id::LocalDefId;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
|
@ -16,6 +15,7 @@ use rustc_middle::mir::FakeReadCause;
|
|||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
|
||||
use rustc_middle::ty::TypeckResults;
|
||||
use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
@ -192,6 +192,27 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// (ouz-a 1005988): Normally `[T] : std::ops::Index<usize>` should be normalized
|
||||
// into [T] but currently `Where` clause stops the normalization process for it,
|
||||
// here we compare types of expr and base in a code without `Where` clause they would be equal
|
||||
// if they are not we don't modify the expr, hence we bypass the ICE
|
||||
fn is_builtin_index(
|
||||
&mut self,
|
||||
typeck_results: &TypeckResults<'tcx>,
|
||||
e: &hir::Expr<'_>,
|
||||
base_ty: Ty<'tcx>,
|
||||
index_ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
if let Some(elem_ty) = base_ty.builtin_index() {
|
||||
let Some(exp_ty) = typeck_results.expr_ty_opt(e) else {return false;};
|
||||
let resolved_exp_ty = self.resolve(exp_ty, &e.span);
|
||||
|
||||
elem_ty == resolved_exp_ty && index_ty == self.fcx.tcx.types.usize
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Similar to operators, indexing is always assumed to be overloaded
|
||||
// Here, correct cases where an indexing expression can be simplified
|
||||
// to use builtin indexing because the index type is known to be
|
||||
|
@ -222,8 +243,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
)
|
||||
});
|
||||
let index_ty = self.fcx.resolve_vars_if_possible(index_ty);
|
||||
let resolved_base_ty = self.resolve(*base_ty, &base.span);
|
||||
|
||||
if base_ty.builtin_index().is_some() && index_ty == self.fcx.tcx.types.usize {
|
||||
if self.is_builtin_index(&typeck_results, e, resolved_base_ty, index_ty) {
|
||||
// Remove the method call record
|
||||
typeck_results.type_dependent_defs_mut().remove(e.hir_id);
|
||||
typeck_results.node_substs_mut().remove(e.hir_id);
|
||||
|
|
|
@ -47,9 +47,11 @@ impl<'tcx> Checker<'tcx> {
|
|||
}
|
||||
|
||||
fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
||||
// Destructors only work on nominal types.
|
||||
if let ty::Adt(..) | ty::Error(_) = tcx.type_of(impl_did).kind() {
|
||||
return;
|
||||
// Destructors only work on local ADT types.
|
||||
match tcx.type_of(impl_did).kind() {
|
||||
ty::Adt(def, _) if def.did().is_local() => return,
|
||||
ty::Error(_) => return,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let sp = match tcx.hir().expect_item(impl_did).kind {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue