}
fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
- let ty = cx.tables().node_type(e.hir_id);
+ let ty = cx.typeck_results().node_type(e.hir_id);
self.check_heap_type(cx, e.span, ty);
}
}
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
let variant = cx
- .tables()
+ .typeck_results()
.pat_ty(pat)
.ty_adt_def()
.expect("struct pattern type is not an ADT")
}
if let PatKind::Binding(binding_annot, _, ident, None) = fieldpat.pat.kind {
if cx.tcx.find_field_index(ident, &variant)
- == Some(cx.tcx.field_index(fieldpat.hir_id, cx.tables()))
+ == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
{
cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
let mut err = lint
if !def_id_is_transmute(cx, did) {
return None;
}
- let sig = cx.tables().node_type(expr.hir_id).fn_sig(cx.tcx);
+ let sig = cx.typeck_results().node_type(expr.hir_id).fn_sig(cx.tcx);
let from = sig.inputs().skip_binder()[0];
let to = sig.output().skip_binder();
return Some((from, to));
impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
use rustc_middle::ty::fold::TypeFoldable;
- use rustc_middle::ty::PredicateKind::*;
+ use rustc_middle::ty::PredicateAtom::*;
if cx.tcx.features().trivial_bounds {
let def_id = cx.tcx.hir().local_def_id(item.hir_id);
let predicates = cx.tcx.predicates_of(def_id);
for &(predicate, span) in predicates.predicates {
- let predicate_kind_name = match predicate.kind() {
+ // We don't actually look inside of the predicate,
+ // so it is safe to skip this binder here.
+ let predicate_kind_name = match predicate.skip_binders() {
Trait(..) => "Trait",
TypeOutlives(..) |
RegionOutlives(..) => "Lifetime",
) -> Vec<ty::Region<'tcx>> {
inferred_outlives
.iter()
- .filter_map(|(pred, _)| match pred.kind() {
- ty::PredicateKind::RegionOutlives(outlives) => {
- let outlives = outlives.skip_binder();
- match outlives.0 {
- ty::ReEarlyBound(ebr) if ebr.index == index => Some(outlives.1),
- _ => None,
- }
- }
+ .filter_map(|(pred, _)| match pred.skip_binders() {
+ ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a {
+ ty::ReEarlyBound(ebr) if ebr.index == index => Some(b),
+ _ => None,
+ },
_ => None,
})
.collect()
) -> Vec<ty::Region<'tcx>> {
inferred_outlives
.iter()
- .filter_map(|(pred, _)| match pred.kind() {
- ty::PredicateKind::TypeOutlives(outlives) => {
- let outlives = outlives.skip_binder();
- outlives.0.is_param(index).then_some(outlives.1)
+ .filter_map(|(pred, _)| match pred.skip_binders() {
+ ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
+ a.is_param(index).then_some(b)
}
_ => None,
})
}
} else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
// Find problematic calls to `MaybeUninit::assume_init`.
- let def_id = cx.tables().type_dependent_def_id(expr.hir_id)?;
+ let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
// This is a call to *some* method named `assume_init`.
// See if the `self` parameter is one of the dangerous constructors.
None
}
+ /// Test if this enum has several actually "existing" variants.
+ /// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist".
+ fn is_multi_variant(adt: &ty::AdtDef) -> bool {
+ // As an approximation, we only count dataless variants. Those are definitely inhabited.
+ let existing_variants = adt.variants.iter().filter(|v| v.fields.is_empty()).count();
+ existing_variants > 1
+ }
+
/// Return `Some` only if we are sure this type does *not*
/// allow zero initialization.
fn ty_find_init_error<'tcx>(
}
// Recurse and checks for some compound types.
Adt(adt_def, substs) if !adt_def.is_union() => {
- // First check f this ADT has a layout attribute (like `NonNull` and friends).
+ // First check if this ADT has a layout attribute (like `NonNull` and friends).
use std::ops::Bound;
match tcx.layout_scalar_valid_range(adt_def.did) {
// We exploit here that `layout_scalar_valid_range` will never
)
})
}
- // Multi-variant enums are tricky: if all but one variant are
- // uninhabited, we might actually do layout like for a single-variant
- // enum, and then even leaving them uninitialized could be okay.
- _ => None, // Conservative fallback for multi-variant enum.
+ // Multi-variant enum.
+ _ => {
+ if init == InitKind::Uninit && is_multi_variant(adt_def) {
+ let span = tcx.def_span(adt_def.did);
+ Some((
+ "enums have to be initialized to a variant".to_string(),
+ Some(span),
+ ))
+ } else {
+ // In principle, for zero-initialization we could figure out which variant corresponds
+ // to tag 0, and check that... but for now we just accept all zero-initializations.
+ None
+ }
+ }
}
}
Tuple(..) => {
// This conjures an instance of a type out of nothing,
// using zeroed or uninitialized memory.
// We are extremely conservative with what we warn about.
- let conjured_ty = cx.tables().expr_ty(expr);
+ let conjured_ty = cx.typeck_results().expr_ty(expr);
if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty, init) {
cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
let mut err = lint.build(&format!(