Make x.py check work
This commit is contained in:
parent
ddfcca48c6
commit
3c2d20ef0b
7 changed files with 211 additions and 134 deletions
|
@ -701,6 +701,10 @@ fn codegen_stmt<'tcx>(
|
||||||
let operand = codegen_operand(fx, operand);
|
let operand = codegen_operand(fx, operand);
|
||||||
operand.unsize_value(fx, lval);
|
operand.unsize_value(fx, lval);
|
||||||
}
|
}
|
||||||
|
Rvalue::Cast(CastKind::DynStar, _, _) => {
|
||||||
|
// FIXME(dyn-star)
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
Rvalue::Discriminant(place) => {
|
Rvalue::Discriminant(place) => {
|
||||||
let place = codegen_place(fx, place);
|
let place = codegen_place(fx, place);
|
||||||
let value = place.to_cvalue(fx);
|
let value = place.to_cvalue(fx);
|
||||||
|
|
|
@ -815,7 +815,7 @@ pub(crate) fn assert_assignable<'tcx>(
|
||||||
);
|
);
|
||||||
// fn(&T) -> for<'l> fn(&'l T) is allowed
|
// fn(&T) -> for<'l> fn(&'l T) is allowed
|
||||||
}
|
}
|
||||||
(&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => {
|
(&ty::Dynamic(from_traits, _, _from_kind), &ty::Dynamic(to_traits, _, _to_kind)) => {
|
||||||
for (from, to) in from_traits.iter().zip(to_traits) {
|
for (from, to) in from_traits.iter().zip(to_traits) {
|
||||||
let from =
|
let from =
|
||||||
fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from);
|
fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from);
|
||||||
|
|
|
@ -1039,7 +1039,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| ty::Ref(_, _, _)
|
| ty::Ref(_, _, _)
|
||||||
| ty::FnDef(_, _)
|
| ty::FnDef(_, _)
|
||||||
| ty::FnPtr(_)
|
| ty::FnPtr(_)
|
||||||
| ty::Dynamic(_, _)
|
| ty::Dynamic(_, _, _)
|
||||||
| ty::Closure(_, _)
|
| ty::Closure(_, _)
|
||||||
| ty::Generator(_, _, _)
|
| ty::Generator(_, _, _)
|
||||||
| ty::GeneratorWitness(_)
|
| ty::GeneratorWitness(_)
|
||||||
|
|
|
@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ty::Dynamic(data, _, ty::TraitObjectRepresentation::Unsized) => {
|
ty::Dynamic(data, _, ty::Dyn) => {
|
||||||
data.iter().find_map(|pred| {
|
data.iter().find_map(|pred| {
|
||||||
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
|
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
|
||||||
&& Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
|
&& Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
|
||||||
|
|
|
@ -2,11 +2,18 @@ use rustc_hir::Expr;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty::{cast::CastKind, Ty};
|
use rustc_middle::ty::{cast::CastKind, Ty};
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::DUMMY_SP;
|
||||||
use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited};
|
use rustc_typeck::check::{
|
||||||
|
cast::{self, CastCheckResult},
|
||||||
|
FnCtxt, Inherited,
|
||||||
|
};
|
||||||
|
|
||||||
// check if the component types of the transmuted collection and the result have different ABI,
|
// check if the component types of the transmuted collection and the result have different ABI,
|
||||||
// size or alignment
|
// size or alignment
|
||||||
pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool {
|
pub(super) fn is_layout_incompatible<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
from: Ty<'tcx>,
|
||||||
|
to: Ty<'tcx>,
|
||||||
|
) -> bool {
|
||||||
if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from)
|
if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from)
|
||||||
&& let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to)
|
&& let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to)
|
||||||
&& let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from))
|
&& let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from))
|
||||||
|
@ -29,7 +36,9 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
|
||||||
from_ty: Ty<'tcx>,
|
from_ty: Ty<'tcx>,
|
||||||
to_ty: Ty<'tcx>,
|
to_ty: Ty<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
|
use CastKind::{
|
||||||
|
AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast,
|
||||||
|
};
|
||||||
matches!(
|
matches!(
|
||||||
check_cast(cx, e, from_ty, to_ty),
|
check_cast(cx, e, from_ty, to_ty),
|
||||||
Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
|
Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
|
||||||
|
@ -40,7 +49,12 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
|
||||||
/// the cast. In certain cases, including some invalid casts from array references
|
/// the cast. In certain cases, including some invalid casts from array references
|
||||||
/// to pointers, this may cause additional errors to be emitted and/or ICE error
|
/// to pointers, this may cause additional errors to be emitted and/or ICE error
|
||||||
/// messages. This function will panic if that occurs.
|
/// messages. This function will panic if that occurs.
|
||||||
fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
|
fn check_cast<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
e: &'tcx Expr<'_>,
|
||||||
|
from_ty: Ty<'tcx>,
|
||||||
|
to_ty: Ty<'tcx>,
|
||||||
|
) -> Option<CastKind> {
|
||||||
let hir_id = e.hir_id;
|
let hir_id = e.hir_id;
|
||||||
let local_def_id = hir_id.owner;
|
let local_def_id = hir_id.owner;
|
||||||
|
|
||||||
|
@ -48,12 +62,9 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>
|
||||||
let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id);
|
let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id);
|
||||||
|
|
||||||
// If we already have errors, we can't be sure we can pointer cast.
|
// If we already have errors, we can't be sure we can pointer cast.
|
||||||
assert!(
|
assert!(!fn_ctxt.errors_reported_since_creation(), "Newly created FnCtxt contained errors");
|
||||||
!fn_ctxt.errors_reported_since_creation(),
|
|
||||||
"Newly created FnCtxt contained errors"
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Ok(check) = CastCheck::new(
|
if let CastCheckResult::Deferred(check) = cast::check_cast(
|
||||||
&fn_ctxt, e, from_ty, to_ty,
|
&fn_ctxt, e, from_ty, to_ty,
|
||||||
// We won't show any error to the user, so we don't care what the span is here.
|
// We won't show any error to the user, so we don't care what the span is here.
|
||||||
DUMMY_SP, DUMMY_SP,
|
DUMMY_SP, DUMMY_SP,
|
||||||
|
|
|
@ -18,7 +18,11 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
type McfResult = Result<(), (Span, Cow<'static, str>)>;
|
type McfResult = Result<(), (Span, Cow<'static, str>)>;
|
||||||
|
|
||||||
pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<RustcVersion>) -> McfResult {
|
pub fn is_min_const_fn<'a, 'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
body: &'a Body<'tcx>,
|
||||||
|
msrv: Option<RustcVersion>,
|
||||||
|
) -> McfResult {
|
||||||
let def_id = body.source.def_id();
|
let def_id = body.source.def_id();
|
||||||
let mut current = def_id;
|
let mut current = def_id;
|
||||||
loop {
|
loop {
|
||||||
|
@ -33,10 +37,18 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv:
|
||||||
| ty::PredicateKind::ConstEquate(..)
|
| ty::PredicateKind::ConstEquate(..)
|
||||||
| ty::PredicateKind::Trait(..)
|
| ty::PredicateKind::Trait(..)
|
||||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
|
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
|
||||||
ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
|
ty::PredicateKind::ObjectSafe(_) => {
|
||||||
ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
|
panic!("object safe predicate on function: {:#?}", predicate)
|
||||||
ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
|
}
|
||||||
ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate),
|
ty::PredicateKind::ClosureKind(..) => {
|
||||||
|
panic!("closure kind predicate on function: {:#?}", predicate)
|
||||||
|
}
|
||||||
|
ty::PredicateKind::Subtype(_) => {
|
||||||
|
panic!("subtype predicate on function: {:#?}", predicate)
|
||||||
|
}
|
||||||
|
ty::PredicateKind::Coerce(_) => {
|
||||||
|
panic!("coerce predicate on function: {:#?}", predicate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match predicates.parent {
|
match predicates.parent {
|
||||||
|
@ -77,22 +89,23 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Ref(_, _, hir::Mutability::Mut) => {
|
ty::Ref(_, _, hir::Mutability::Mut) => {
|
||||||
return Err((span, "mutable references in const fn are unstable".into()));
|
return Err((span, "mutable references in const fn are unstable".into()));
|
||||||
},
|
}
|
||||||
ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
|
ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
|
||||||
ty::FnPtr(..) => {
|
ty::FnPtr(..) => {
|
||||||
return Err((span, "function pointers in const fn are unstable".into()));
|
return Err((span, "function pointers in const fn are unstable".into()));
|
||||||
},
|
}
|
||||||
ty::Dynamic(preds, _) => {
|
ty::Dynamic(preds, _, _) => {
|
||||||
for pred in preds.iter() {
|
for pred in preds.iter() {
|
||||||
match pred.skip_binder() {
|
match pred.skip_binder() {
|
||||||
ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => {
|
ty::ExistentialPredicate::AutoTrait(_)
|
||||||
|
| ty::ExistentialPredicate::Projection(_) => {
|
||||||
return Err((
|
return Err((
|
||||||
span,
|
span,
|
||||||
"trait bounds other than `Sized` \
|
"trait bounds other than `Sized` \
|
||||||
on const fn parameters are unstable"
|
on const fn parameters are unstable"
|
||||||
.into(),
|
.into(),
|
||||||
));
|
));
|
||||||
},
|
}
|
||||||
ty::ExistentialPredicate::Trait(trait_ref) => {
|
ty::ExistentialPredicate::Trait(trait_ref) => {
|
||||||
if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
|
if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
|
||||||
return Err((
|
return Err((
|
||||||
|
@ -102,11 +115,11 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
|
||||||
.into(),
|
.into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -120,10 +133,13 @@ fn check_rvalue<'tcx>(
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> McfResult {
|
) -> McfResult {
|
||||||
match rvalue {
|
match rvalue {
|
||||||
Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
|
Rvalue::ThreadLocalRef(_) => {
|
||||||
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
|
Err((span, "cannot access thread local storage in const fn".into()))
|
||||||
check_place(tcx, *place, span, body)
|
}
|
||||||
},
|
Rvalue::Len(place)
|
||||||
|
| Rvalue::Discriminant(place)
|
||||||
|
| Rvalue::Ref(_, _, place)
|
||||||
|
| Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, body),
|
||||||
Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body),
|
Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body),
|
||||||
Rvalue::Repeat(operand, _)
|
Rvalue::Repeat(operand, _)
|
||||||
| Rvalue::Use(operand)
|
| Rvalue::Use(operand)
|
||||||
|
@ -136,7 +152,9 @@ fn check_rvalue<'tcx>(
|
||||||
) => check_operand(tcx, operand, span, body),
|
) => check_operand(tcx, operand, span, body),
|
||||||
Rvalue::Cast(
|
Rvalue::Cast(
|
||||||
CastKind::Pointer(
|
CastKind::Pointer(
|
||||||
PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer,
|
PointerCast::UnsafeFnPointer
|
||||||
|
| PointerCast::ClosureFnPointer(_)
|
||||||
|
| PointerCast::ReifyFnPointer,
|
||||||
),
|
),
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
|
@ -146,7 +164,10 @@ fn check_rvalue<'tcx>(
|
||||||
deref_ty.ty
|
deref_ty.ty
|
||||||
} else {
|
} else {
|
||||||
// We cannot allow this for now.
|
// We cannot allow this for now.
|
||||||
return Err((span, "unsizing casts are only allowed for references right now".into()));
|
return Err((
|
||||||
|
span,
|
||||||
|
"unsizing casts are only allowed for references right now".into(),
|
||||||
|
));
|
||||||
};
|
};
|
||||||
let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
|
let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
|
||||||
if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
|
if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
|
||||||
|
@ -157,10 +178,14 @@ fn check_rvalue<'tcx>(
|
||||||
// We just can't allow trait objects until we have figured out trait method calls.
|
// We just can't allow trait objects until we have figured out trait method calls.
|
||||||
Err((span, "unsizing casts are not allowed in const fn".into()))
|
Err((span, "unsizing casts are not allowed in const fn".into()))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
|
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
|
||||||
Err((span, "casting pointers to ints is unstable in const fn".into()))
|
Err((span, "casting pointers to ints is unstable in const fn".into()))
|
||||||
},
|
}
|
||||||
|
Rvalue::Cast(CastKind::DynStar, _, _) => {
|
||||||
|
// FIXME(dyn-star)
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
// binops are fine on integers
|
// binops are fine on integers
|
||||||
Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
|
Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
|
||||||
check_operand(tcx, lhs, span, body)?;
|
check_operand(tcx, lhs, span, body)?;
|
||||||
|
@ -169,13 +194,12 @@ fn check_rvalue<'tcx>(
|
||||||
if ty.is_integral() || ty.is_bool() || ty.is_char() {
|
if ty.is_integral() || ty.is_bool() || ty.is_char() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err((
|
Err((span, "only int, `bool` and `char` operations are stable in const fn".into()))
|
||||||
span,
|
|
||||||
"only int, `bool` and `char` operations are stable in const fn".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()),
|
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Rvalue::UnaryOp(_, operand) => {
|
Rvalue::UnaryOp(_, operand) => {
|
||||||
let ty = operand.ty(body, tcx);
|
let ty = operand.ty(body, tcx);
|
||||||
if ty.is_integral() || ty.is_bool() {
|
if ty.is_integral() || ty.is_bool() {
|
||||||
|
@ -183,13 +207,13 @@ fn check_rvalue<'tcx>(
|
||||||
} else {
|
} else {
|
||||||
Err((span, "only int and `bool` operations are stable in const fn".into()))
|
Err((span, "only int and `bool` operations are stable in const fn".into()))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Rvalue::Aggregate(_, operands) => {
|
Rvalue::Aggregate(_, operands) => {
|
||||||
for operand in operands {
|
for operand in operands {
|
||||||
check_operand(tcx, operand, span, body)?;
|
check_operand(tcx, operand, span, body)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +228,7 @@ fn check_statement<'tcx>(
|
||||||
StatementKind::Assign(box (place, rval)) => {
|
StatementKind::Assign(box (place, rval)) => {
|
||||||
check_place(tcx, *place, span, body)?;
|
check_place(tcx, *place, span, body)?;
|
||||||
check_rvalue(tcx, body, def_id, rval, span)
|
check_rvalue(tcx, body, def_id, rval, span)
|
||||||
},
|
}
|
||||||
|
|
||||||
StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body),
|
StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body),
|
||||||
// just an assignment
|
// just an assignment
|
||||||
|
@ -214,14 +238,15 @@ fn check_statement<'tcx>(
|
||||||
|
|
||||||
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body),
|
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body),
|
||||||
|
|
||||||
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
|
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||||
rustc_middle::mir::CopyNonOverlapping { dst, src, count },
|
dst,
|
||||||
)) => {
|
src,
|
||||||
|
count,
|
||||||
|
}) => {
|
||||||
check_operand(tcx, dst, span, body)?;
|
check_operand(tcx, dst, span, body)?;
|
||||||
check_operand(tcx, src, span, body)?;
|
check_operand(tcx, src, span, body)?;
|
||||||
check_operand(tcx, count, span, body)
|
check_operand(tcx, count, span, body)
|
||||||
},
|
}
|
||||||
|
|
||||||
// These are all NOPs
|
// These are all NOPs
|
||||||
StatementKind::StorageLive(_)
|
StatementKind::StorageLive(_)
|
||||||
| StatementKind::StorageDead(_)
|
| StatementKind::StorageDead(_)
|
||||||
|
@ -232,7 +257,12 @@ fn check_statement<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
|
fn check_operand<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
operand: &Operand<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
body: &Body<'tcx>,
|
||||||
|
) -> McfResult {
|
||||||
match operand {
|
match operand {
|
||||||
Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body),
|
Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body),
|
||||||
Operand::Constant(c) => match c.check_static_ptr(tcx) {
|
Operand::Constant(c) => match c.check_static_ptr(tcx) {
|
||||||
|
@ -242,7 +272,12 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
|
fn check_place<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
place: Place<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
body: &Body<'tcx>,
|
||||||
|
) -> McfResult {
|
||||||
let mut cursor = place.projection.as_ref();
|
let mut cursor = place.projection.as_ref();
|
||||||
while let [ref proj_base @ .., elem] = *cursor {
|
while let [ref proj_base @ .., elem] = *cursor {
|
||||||
cursor = proj_base;
|
cursor = proj_base;
|
||||||
|
@ -255,12 +290,12 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B
|
||||||
return Err((span, "accessing union fields is unstable".into()));
|
return Err((span, "accessing union fields is unstable".into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
ProjectionElem::ConstantIndex { .. }
|
ProjectionElem::ConstantIndex { .. }
|
||||||
| ProjectionElem::Downcast(..)
|
| ProjectionElem::Downcast(..)
|
||||||
| ProjectionElem::Subslice { .. }
|
| ProjectionElem::Subslice { .. }
|
||||||
| ProjectionElem::Deref
|
| ProjectionElem::Deref
|
||||||
| ProjectionElem::Index(_) => {},
|
| ProjectionElem::Index(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,18 +321,16 @@ fn check_terminator<'a, 'tcx>(
|
||||||
TerminatorKind::DropAndReplace { place, value, .. } => {
|
TerminatorKind::DropAndReplace { place, value, .. } => {
|
||||||
check_place(tcx, *place, span, body)?;
|
check_place(tcx, *place, span, body)?;
|
||||||
check_operand(tcx, value, span, body)
|
check_operand(tcx, value, span, body)
|
||||||
},
|
}
|
||||||
|
|
||||||
TerminatorKind::SwitchInt {
|
TerminatorKind::SwitchInt { discr, switch_ty: _, targets: _ } => {
|
||||||
discr,
|
check_operand(tcx, discr, span, body)
|
||||||
switch_ty: _,
|
}
|
||||||
targets: _,
|
|
||||||
} => check_operand(tcx, discr, span, body),
|
|
||||||
|
|
||||||
TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
|
TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
|
||||||
TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
|
TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
|
||||||
Err((span, "const fn generators are unstable".into()))
|
Err((span, "const fn generators are unstable".into()))
|
||||||
},
|
}
|
||||||
|
|
||||||
TerminatorKind::Call {
|
TerminatorKind::Call {
|
||||||
func,
|
func,
|
||||||
|
@ -342,17 +375,15 @@ fn check_terminator<'a, 'tcx>(
|
||||||
} else {
|
} else {
|
||||||
Err((span, "can only call other const fns within const fn".into()))
|
Err((span, "can only call other const fns within const fn".into()))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
TerminatorKind::Assert {
|
TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => {
|
||||||
cond,
|
check_operand(tcx, cond, span, body)
|
||||||
expected: _,
|
}
|
||||||
msg: _,
|
|
||||||
target: _,
|
|
||||||
cleanup: _,
|
|
||||||
} => check_operand(tcx, cond, span, body),
|
|
||||||
|
|
||||||
TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
|
TerminatorKind::InlineAsm { .. } => {
|
||||||
|
Err((span, "cannot use inline assembly in const fn".into()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,9 @@ use rustc_lint::LateContext;
|
||||||
use rustc_middle::mir::interpret::{ConstValue, Scalar};
|
use rustc_middle::mir::interpret::{ConstValue, Scalar};
|
||||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
|
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, ProjectionTy,
|
self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind,
|
||||||
Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr,
|
ProjectionTy, Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
|
||||||
|
UintTy, VariantDef, VariantDiscr,
|
||||||
};
|
};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
|
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
|
||||||
|
@ -166,9 +167,7 @@ pub fn implements_trait_with_env<'tcx>(
|
||||||
}
|
}
|
||||||
let ty_params = tcx.mk_substs(ty_params.iter());
|
let ty_params = tcx.mk_substs(ty_params.iter());
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
tcx.infer_ctxt().enter(|infcx| {
|
||||||
infcx
|
infcx.type_implements_trait(trait_id, ty, ty_params, param_env).must_apply_modulo_regions()
|
||||||
.type_implements_trait(trait_id, ty, ty_params, param_env)
|
|
||||||
.must_apply_modulo_regions()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,11 +184,14 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use),
|
ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use),
|
||||||
ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use),
|
ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use),
|
||||||
ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
|
ty::Slice(ty)
|
||||||
|
| ty::Array(ty, _)
|
||||||
|
| ty::RawPtr(ty::TypeAndMut { ty, .. })
|
||||||
|
| ty::Ref(_, ty, _) => {
|
||||||
// for the Array case we don't need to care for the len == 0 case
|
// for the Array case we don't need to care for the len == 0 case
|
||||||
// because we don't want to lint functions returning empty arrays
|
// because we don't want to lint functions returning empty arrays
|
||||||
is_must_use_ty(cx, *ty)
|
is_must_use_ty(cx, *ty)
|
||||||
},
|
}
|
||||||
ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
|
ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
|
||||||
ty::Opaque(def_id, _) => {
|
ty::Opaque(def_id, _) => {
|
||||||
for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
|
for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
|
||||||
|
@ -200,8 +202,8 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
},
|
}
|
||||||
ty::Dynamic(binder, _) => {
|
ty::Dynamic(binder, _, _) => {
|
||||||
for predicate in binder.iter() {
|
for predicate in binder.iter() {
|
||||||
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
|
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
|
||||||
if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) {
|
if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) {
|
||||||
|
@ -210,7 +212,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
},
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +222,11 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
// not succeed
|
// not succeed
|
||||||
/// Checks if `Ty` is normalizable. This function is useful
|
/// Checks if `Ty` is normalizable. This function is useful
|
||||||
/// to avoid crashes on `layout_of`.
|
/// to avoid crashes on `layout_of`.
|
||||||
pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
|
pub fn is_normalizable<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> bool {
|
||||||
is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default())
|
is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,15 +246,14 @@ fn is_normalizable_helper<'tcx>(
|
||||||
if infcx.at(&cause, param_env).normalize(ty).is_ok() {
|
if infcx.at(&cause, param_env).normalize(ty).is_ok() {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Adt(def, substs) => def.variants().iter().all(|variant| {
|
ty::Adt(def, substs) => def.variants().iter().all(|variant| {
|
||||||
variant
|
variant.fields.iter().all(|field| {
|
||||||
.fields
|
is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)
|
||||||
.iter()
|
})
|
||||||
.all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
|
|
||||||
}),
|
}),
|
||||||
_ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
|
_ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
|
||||||
GenericArgKind::Type(inner_ty) if inner_ty != ty => {
|
GenericArgKind::Type(inner_ty) if inner_ty != ty => {
|
||||||
is_normalizable_helper(cx, param_env, inner_ty, cache)
|
is_normalizable_helper(cx, param_env, inner_ty, cache)
|
||||||
},
|
}
|
||||||
_ => true, // if inner_ty == ty, we've already checked it
|
_ => true, // if inner_ty == ty, we've already checked it
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -273,7 +278,9 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
|
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
|
||||||
ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true,
|
ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true,
|
||||||
ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
|
ty::Array(inner_type, _) | ty::Slice(inner_type) => {
|
||||||
|
is_recursively_primitive_type(inner_type)
|
||||||
|
}
|
||||||
ty::Tuple(inner_types) => inner_types.iter().all(is_recursively_primitive_type),
|
ty::Tuple(inner_types) => inner_types.iter().all(is_recursively_primitive_type),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
@ -313,11 +320,9 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb
|
||||||
/// Returns `false` if the `LangItem` is not defined.
|
/// Returns `false` if the `LangItem` is not defined.
|
||||||
pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
|
pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Adt(adt, _) => cx
|
ty::Adt(adt, _) => {
|
||||||
.tcx
|
cx.tcx.lang_items().require(lang_item).map_or(false, |li| li == adt.did())
|
||||||
.lang_items()
|
}
|
||||||
.require(lang_item)
|
|
||||||
.map_or(false, |li| li == adt.did()),
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -342,7 +347,11 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
|
||||||
/// deallocate memory. For these types, and composites containing them, changing the drop order
|
/// deallocate memory. For these types, and composites containing them, changing the drop order
|
||||||
/// won't result in any observable side effects.
|
/// won't result in any observable side effects.
|
||||||
pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
fn needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet<Ty<'tcx>>) -> bool {
|
fn needs_ordered_drop_inner<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
seen: &mut FxHashSet<Ty<'tcx>>,
|
||||||
|
) -> bool {
|
||||||
if !seen.insert(ty) {
|
if !seen.insert(ty) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -393,11 +402,7 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
/// removed.
|
/// removed.
|
||||||
pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
|
pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
|
||||||
fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
|
fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
|
||||||
if let ty::Ref(_, ty, _) = ty.kind() {
|
if let ty::Ref(_, ty, _) = ty.kind() { peel(*ty, count + 1) } else { (ty, count) }
|
||||||
peel(*ty, count + 1)
|
|
||||||
} else {
|
|
||||||
(ty, count)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
peel(ty, 0)
|
peel(ty, 0)
|
||||||
}
|
}
|
||||||
|
@ -452,17 +457,18 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
substs_a
|
substs_a.iter().zip(substs_b.iter()).all(|(arg_a, arg_b)| {
|
||||||
.iter()
|
match (arg_a.unpack(), arg_b.unpack()) {
|
||||||
.zip(substs_b.iter())
|
(GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => {
|
||||||
.all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
|
inner_a == inner_b
|
||||||
(GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
|
}
|
||||||
(GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
|
(GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
|
||||||
same_type_and_consts(type_a, type_b)
|
same_type_and_consts(type_a, type_b)
|
||||||
},
|
}
|
||||||
_ => true,
|
_ => true,
|
||||||
})
|
}
|
||||||
},
|
})
|
||||||
|
}
|
||||||
_ => a == b,
|
_ => a == b,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -478,7 +484,10 @@ pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an iterator over all predicates which apply to the given item.
|
/// Gets an iterator over all predicates which apply to the given item.
|
||||||
pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(Predicate<'_>, Span)> {
|
pub fn all_predicates_of(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
id: DefId,
|
||||||
|
) -> impl Iterator<Item = &(Predicate<'_>, Span)> {
|
||||||
let mut next_id = Some(id);
|
let mut next_id = Some(id);
|
||||||
iter::from_fn(move || {
|
iter::from_fn(move || {
|
||||||
next_id.take().map(|id| {
|
next_id.take().map(|id| {
|
||||||
|
@ -508,7 +517,7 @@ impl<'tcx> ExprFnSig<'tcx> {
|
||||||
} else {
|
} else {
|
||||||
Some(sig.input(i))
|
Some(sig.input(i))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])),
|
Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])),
|
||||||
Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
|
Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
|
||||||
}
|
}
|
||||||
|
@ -517,7 +526,10 @@ impl<'tcx> ExprFnSig<'tcx> {
|
||||||
/// Gets the argument type at the given offset. For closures this will also get the type as
|
/// Gets the argument type at the given offset. For closures this will also get the type as
|
||||||
/// written. This will return `None` when the index is out of bounds only for variadic
|
/// written. This will return `None` when the index is out of bounds only for variadic
|
||||||
/// functions, otherwise this will panic.
|
/// functions, otherwise this will panic.
|
||||||
pub fn input_with_hir(self, i: usize) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> {
|
pub fn input_with_hir(
|
||||||
|
self,
|
||||||
|
i: usize,
|
||||||
|
) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> {
|
||||||
match self {
|
match self {
|
||||||
Self::Sig(sig, _) => {
|
Self::Sig(sig, _) => {
|
||||||
if sig.c_variadic() {
|
if sig.c_variadic() {
|
||||||
|
@ -528,7 +540,7 @@ impl<'tcx> ExprFnSig<'tcx> {
|
||||||
} else {
|
} else {
|
||||||
Some((None, sig.input(i)))
|
Some((None, sig.input(i)))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Self::Closure(decl, sig) => Some((
|
Self::Closure(decl, sig) => Some((
|
||||||
decl.and_then(|decl| decl.inputs.get(i)),
|
decl.and_then(|decl| decl.inputs.get(i)),
|
||||||
sig.input(0).map_bound(|ty| ty.tuple_fields()[i]),
|
sig.input(0).map_bound(|ty| ty.tuple_fields()[i]),
|
||||||
|
@ -547,17 +559,15 @@ impl<'tcx> ExprFnSig<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn predicates_id(&self) -> Option<DefId> {
|
pub fn predicates_id(&self) -> Option<DefId> {
|
||||||
if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self {
|
if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { id } else { None }
|
||||||
id
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the expression is function like, get the signature for it.
|
/// If the expression is function like, get the signature for it.
|
||||||
pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
|
pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
|
||||||
if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) {
|
if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) =
|
||||||
|
path_res(cx, expr)
|
||||||
|
{
|
||||||
Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id)))
|
Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id)))
|
||||||
} else {
|
} else {
|
||||||
ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs())
|
ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs())
|
||||||
|
@ -571,15 +581,17 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
|
||||||
}
|
}
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Closure(id, subs) => {
|
ty::Closure(id, subs) => {
|
||||||
let decl = id
|
let decl = id.as_local().and_then(|id| {
|
||||||
.as_local()
|
cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id))
|
||||||
.and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)));
|
});
|
||||||
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
|
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
|
||||||
},
|
}
|
||||||
ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
|
ty::FnDef(id, subs) => {
|
||||||
|
Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id)))
|
||||||
|
}
|
||||||
ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)),
|
ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)),
|
||||||
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
|
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
|
||||||
ty::Dynamic(bounds, _) => {
|
ty::Dynamic(bounds, _, _) => {
|
||||||
let lang_items = cx.tcx.lang_items();
|
let lang_items = cx.tcx.lang_items();
|
||||||
match bounds.principal() {
|
match bounds.principal() {
|
||||||
Some(bound)
|
Some(bound)
|
||||||
|
@ -589,16 +601,19 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
|
||||||
{
|
{
|
||||||
let output = bounds
|
let output = bounds
|
||||||
.projection_bounds()
|
.projection_bounds()
|
||||||
.find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id()))
|
.find(|p| {
|
||||||
|
lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id())
|
||||||
|
})
|
||||||
.map(|p| p.map_bound(|p| p.term.ty().unwrap()));
|
.map(|p| p.map_bound(|p| p.term.ty().unwrap()));
|
||||||
Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None))
|
Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None))
|
||||||
},
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
|
ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
|
||||||
Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
|
Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
|
||||||
_ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
|
_ => sig_for_projection(cx, proj)
|
||||||
|
.or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
|
||||||
},
|
},
|
||||||
ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None),
|
ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -629,7 +644,7 @@ fn sig_from_bounds<'tcx>(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
inputs = Some(i);
|
inputs = Some(i);
|
||||||
},
|
}
|
||||||
PredicateKind::Projection(p)
|
PredicateKind::Projection(p)
|
||||||
if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
|
if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
|
||||||
&& p.projection_ty.self_ty() == ty =>
|
&& p.projection_ty.self_ty() == ty =>
|
||||||
|
@ -639,7 +654,7 @@ fn sig_from_bounds<'tcx>(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
output = Some(pred.kind().rebind(p.term.ty().unwrap()));
|
output = Some(pred.kind().rebind(p.term.ty().unwrap()));
|
||||||
},
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -647,7 +662,10 @@ fn sig_from_bounds<'tcx>(
|
||||||
inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id))
|
inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option<ExprFnSig<'tcx>> {
|
fn sig_for_projection<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
ty: ProjectionTy<'tcx>,
|
||||||
|
) -> Option<ExprFnSig<'tcx>> {
|
||||||
let mut inputs = None;
|
let mut inputs = None;
|
||||||
let mut output = None;
|
let mut output = None;
|
||||||
let lang_items = cx.tcx.lang_items();
|
let lang_items = cx.tcx.lang_items();
|
||||||
|
@ -673,8 +691,10 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
inputs = Some(i);
|
inputs = Some(i);
|
||||||
},
|
}
|
||||||
PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => {
|
PredicateKind::Projection(p)
|
||||||
|
if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() =>
|
||||||
|
{
|
||||||
if output.is_some() {
|
if output.is_some() {
|
||||||
// Multiple different fn trait impls. Is this even allowed?
|
// Multiple different fn trait impls. Is this even allowed?
|
||||||
return None;
|
return None;
|
||||||
|
@ -683,7 +703,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
|
||||||
pred.map_bound(|pred| pred.kind().rebind(p.term.ty().unwrap()))
|
pred.map_bound(|pred| pred.kind().rebind(p.term.ty().unwrap()))
|
||||||
.subst(cx.tcx, ty.substs),
|
.subst(cx.tcx, ty.substs),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -777,7 +797,10 @@ pub fn for_each_top_level_late_bound_region<B>(
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn visit_binder<T: TypeVisitable<'tcx>>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow<Self::BreakTy> {
|
fn visit_binder<T: TypeVisitable<'tcx>>(
|
||||||
|
&mut self,
|
||||||
|
t: &Binder<'tcx, T>,
|
||||||
|
) -> ControlFlow<Self::BreakTy> {
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
let res = t.super_visit_with(self);
|
let res = t.super_visit_with(self);
|
||||||
self.index -= 1;
|
self.index -= 1;
|
||||||
|
@ -791,19 +814,27 @@ pub fn for_each_top_level_late_bound_region<B>(
|
||||||
pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> {
|
pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> {
|
||||||
match res {
|
match res {
|
||||||
Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()),
|
Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()),
|
||||||
Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)),
|
Res::Def(DefKind::Variant, id) => {
|
||||||
Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()),
|
Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id))
|
||||||
|
}
|
||||||
|
Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => {
|
||||||
|
Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant())
|
||||||
|
}
|
||||||
Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => {
|
Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => {
|
||||||
let var_id = cx.tcx.parent(id);
|
let var_id = cx.tcx.parent(id);
|
||||||
Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id))
|
Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id))
|
||||||
},
|
}
|
||||||
Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()),
|
Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`.
|
/// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`.
|
||||||
pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [Predicate<'_>]) -> bool {
|
pub fn ty_is_fn_once_param<'tcx>(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
predicates: &'tcx [Predicate<'_>],
|
||||||
|
) -> bool {
|
||||||
let ty::Param(ty) = *ty.kind() else {
|
let ty::Param(ty) = *ty.kind() else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue