add some msrv checks in is_min_const_fn
This commit is contained in:
parent
befb659145
commit
1b7fc5f5aa
@ -26,7 +26,8 @@ macro_rules! msrv_aliases {
|
|||||||
1,63,0 { CLONE_INTO }
|
1,63,0 { CLONE_INTO }
|
||||||
1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
|
1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
|
||||||
1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST }
|
1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST }
|
||||||
1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
|
1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF }
|
||||||
|
1,56,0 { CONST_FN_UNION }
|
||||||
1,55,0 { SEEK_REWIND }
|
1,55,0 { SEEK_REWIND }
|
||||||
1,54,0 { INTO_KEYS }
|
1,54,0 { INTO_KEYS }
|
||||||
1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
|
1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// of terminologies might not be relevant in the context of Clippy. Note that its behavior might
|
// of terminologies might not be relevant in the context of Clippy. Note that its behavior might
|
||||||
// differ from the time of `rustc` even if the name stays the same.
|
// differ from the time of `rustc` even if the name stays the same.
|
||||||
|
|
||||||
use clippy_config::msrvs::Msrv;
|
use clippy_config::msrvs::{self, Msrv};
|
||||||
use hir::LangItem;
|
use hir::LangItem;
|
||||||
use rustc_attr::StableSince;
|
use rustc_attr::StableSince;
|
||||||
use rustc_const_eval::transform::check_consts::ConstCx;
|
use rustc_const_eval::transform::check_consts::ConstCx;
|
||||||
@ -42,7 +42,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
|
|||||||
for bb in &*body.basic_blocks {
|
for bb in &*body.basic_blocks {
|
||||||
check_terminator(tcx, body, bb.terminator(), msrv)?;
|
check_terminator(tcx, body, bb.terminator(), msrv)?;
|
||||||
for stmt in &bb.statements {
|
for stmt in &bb.statements {
|
||||||
check_statement(tcx, body, def_id, stmt)?;
|
check_statement(tcx, body, def_id, stmt, msrv)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -102,13 +102,14 @@ fn check_rvalue<'tcx>(
|
|||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
rvalue: &Rvalue<'tcx>,
|
rvalue: &Rvalue<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
msrv: &Msrv,
|
||||||
) -> McfResult {
|
) -> McfResult {
|
||||||
match rvalue {
|
match rvalue {
|
||||||
Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
|
Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
|
||||||
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
|
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
|
||||||
check_place(tcx, *place, span, body)
|
check_place(tcx, *place, span, body, msrv)
|
||||||
},
|
},
|
||||||
Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body),
|
Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
|
||||||
Rvalue::Repeat(operand, _)
|
Rvalue::Repeat(operand, _)
|
||||||
| Rvalue::Use(operand)
|
| Rvalue::Use(operand)
|
||||||
| Rvalue::Cast(
|
| Rvalue::Cast(
|
||||||
@ -122,7 +123,7 @@ fn check_rvalue<'tcx>(
|
|||||||
| CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer),
|
| CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer),
|
||||||
operand,
|
operand,
|
||||||
_,
|
_,
|
||||||
) => check_operand(tcx, operand, span, body),
|
) => check_operand(tcx, operand, span, body, msrv),
|
||||||
Rvalue::Cast(
|
Rvalue::Cast(
|
||||||
CastKind::PointerCoercion(
|
CastKind::PointerCoercion(
|
||||||
PointerCoercion::UnsafeFnPointer
|
PointerCoercion::UnsafeFnPointer
|
||||||
@ -141,7 +142,7 @@ fn check_rvalue<'tcx>(
|
|||||||
};
|
};
|
||||||
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() {
|
||||||
check_operand(tcx, op, span, body)?;
|
check_operand(tcx, op, span, body, msrv)?;
|
||||||
// Casting/coercing things to slices is fine.
|
// Casting/coercing things to slices is fine.
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -162,8 +163,8 @@ fn check_rvalue<'tcx>(
|
|||||||
)),
|
)),
|
||||||
// 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, msrv)?;
|
||||||
check_operand(tcx, rhs, span, body)?;
|
check_operand(tcx, rhs, span, body, msrv)?;
|
||||||
let ty = lhs.ty(body, tcx);
|
let ty = lhs.ty(body, tcx);
|
||||||
if ty.is_integral() || ty.is_bool() || ty.is_char() {
|
if ty.is_integral() || ty.is_bool() || ty.is_char() {
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -179,14 +180,14 @@ fn check_rvalue<'tcx>(
|
|||||||
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() {
|
||||||
check_operand(tcx, operand, span, body)
|
check_operand(tcx, operand, span, body, msrv)
|
||||||
} 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, msrv)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
@ -198,28 +199,29 @@ fn check_statement<'tcx>(
|
|||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
statement: &Statement<'tcx>,
|
statement: &Statement<'tcx>,
|
||||||
|
msrv: &Msrv,
|
||||||
) -> McfResult {
|
) -> McfResult {
|
||||||
let span = statement.source_info.span;
|
let span = statement.source_info.span;
|
||||||
match &statement.kind {
|
match &statement.kind {
|
||||||
StatementKind::Assign(box (place, rval)) => {
|
StatementKind::Assign(box (place, rval)) => {
|
||||||
check_place(tcx, *place, span, body)?;
|
check_place(tcx, *place, span, body, msrv)?;
|
||||||
check_rvalue(tcx, body, def_id, rval, span)
|
check_rvalue(tcx, body, def_id, rval, span, msrv)
|
||||||
},
|
},
|
||||||
|
|
||||||
StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body),
|
StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body, msrv),
|
||||||
// just an assignment
|
// just an assignment
|
||||||
StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
|
StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
|
||||||
check_place(tcx, **place, span, body)
|
check_place(tcx, **place, span, body, msrv)
|
||||||
},
|
},
|
||||||
|
|
||||||
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body),
|
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body, msrv),
|
||||||
|
|
||||||
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
|
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
|
||||||
rustc_middle::mir::CopyNonOverlapping { dst, src, count },
|
rustc_middle::mir::CopyNonOverlapping { dst, src, count },
|
||||||
)) => {
|
)) => {
|
||||||
check_operand(tcx, dst, span, body)?;
|
check_operand(tcx, dst, span, body, msrv)?;
|
||||||
check_operand(tcx, src, span, body)?;
|
check_operand(tcx, src, span, body, msrv)?;
|
||||||
check_operand(tcx, count, span, body)
|
check_operand(tcx, count, span, body, msrv)
|
||||||
},
|
},
|
||||||
// These are all NOPs
|
// These are all NOPs
|
||||||
StatementKind::StorageLive(_)
|
StatementKind::StorageLive(_)
|
||||||
@ -233,7 +235,13 @@ 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>,
|
||||||
|
msrv: &Msrv,
|
||||||
|
) -> McfResult {
|
||||||
match operand {
|
match operand {
|
||||||
Operand::Move(place) => {
|
Operand::Move(place) => {
|
||||||
if !place.projection.as_ref().is_empty()
|
if !place.projection.as_ref().is_empty()
|
||||||
@ -245,9 +253,9 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
check_place(tcx, *place, span, body)
|
check_place(tcx, *place, span, body, msrv)
|
||||||
},
|
},
|
||||||
Operand::Copy(place) => check_place(tcx, *place, span, body),
|
Operand::Copy(place) => check_place(tcx, *place, span, body, msrv),
|
||||||
Operand::Constant(c) => match c.check_static_ptr(tcx) {
|
Operand::Constant(c) => match c.check_static_ptr(tcx) {
|
||||||
Some(_) => Err((span, "cannot access `static` items in const fn".into())),
|
Some(_) => Err((span, "cannot access `static` items in const fn".into())),
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
@ -255,23 +263,27 @@ 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>, msrv: &Msrv) -> McfResult {
|
||||||
for (base, elem) in place.as_ref().iter_projections() {
|
for (base, elem) in place.as_ref().iter_projections() {
|
||||||
match elem {
|
match elem {
|
||||||
ProjectionElem::Field(..) => {
|
ProjectionElem::Field(..) => {
|
||||||
let base_ty = base.ty(body, tcx).ty;
|
if base.ty(body, tcx).ty.is_union() && !msrv.meets(msrvs::CONST_FN_UNION) {
|
||||||
if let Some(def) = base_ty.ty_adt_def() {
|
|
||||||
// No union field accesses in `const fn`
|
|
||||||
if def.is_union() {
|
|
||||||
return Err((span, "accessing union fields is unstable".into()));
|
return Err((span, "accessing union fields is unstable".into()));
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
ProjectionElem::Deref => match base.ty(body, tcx).ty.kind() {
|
||||||
|
ty::RawPtr(_, hir::Mutability::Mut) => {
|
||||||
|
return Err((span, "dereferencing raw mut pointer in const fn is unstable".into()));
|
||||||
|
},
|
||||||
|
ty::RawPtr(_, hir::Mutability::Not) if !msrv.meets(msrvs::CONST_RAW_PTR_DEREF) => {
|
||||||
|
return Err((span, "dereferencing raw const pointer in const fn is unstable".into()));
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
},
|
},
|
||||||
ProjectionElem::ConstantIndex { .. }
|
ProjectionElem::ConstantIndex { .. }
|
||||||
| ProjectionElem::OpaqueCast(..)
|
| ProjectionElem::OpaqueCast(..)
|
||||||
| ProjectionElem::Downcast(..)
|
| ProjectionElem::Downcast(..)
|
||||||
| ProjectionElem::Subslice { .. }
|
| ProjectionElem::Subslice { .. }
|
||||||
| ProjectionElem::Deref
|
|
||||||
| ProjectionElem::Subtype(_)
|
| ProjectionElem::Subtype(_)
|
||||||
| ProjectionElem::Index(_) => {},
|
| ProjectionElem::Index(_) => {},
|
||||||
}
|
}
|
||||||
@ -304,7 +316,7 @@ fn check_terminator<'tcx>(
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
|
TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body, msrv),
|
||||||
TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => {
|
TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => {
|
||||||
Err((span, "const fn coroutines are unstable".into()))
|
Err((span, "const fn coroutines are unstable".into()))
|
||||||
},
|
},
|
||||||
@ -341,10 +353,10 @@ fn check_terminator<'tcx>(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
check_operand(tcx, func, span, body)?;
|
check_operand(tcx, func, span, body, msrv)?;
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
check_operand(tcx, &arg.node, span, body)?;
|
check_operand(tcx, &arg.node, span, body, msrv)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -357,7 +369,7 @@ fn check_terminator<'tcx>(
|
|||||||
msg: _,
|
msg: _,
|
||||||
target: _,
|
target: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
} => check_operand(tcx, cond, span, body),
|
} => check_operand(tcx, cond, span, body, msrv),
|
||||||
TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
|
TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,23 @@ union U {
|
|||||||
f: u32,
|
f: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not lint because accessing union fields from const functions is unstable
|
// Do not lint because accessing union fields from const functions is unstable in 1.55
|
||||||
|
#[clippy::msrv = "1.55"]
|
||||||
fn h(u: U) -> u32 {
|
fn h(u: U) -> u32 {
|
||||||
unsafe { u.f }
|
unsafe { u.f }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod msrv {
|
||||||
|
struct Foo(*const u8, *mut u8);
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
#[clippy::msrv = "1.57"]
|
||||||
|
fn deref_ptr_cannot_be_const(self) -> usize {
|
||||||
|
unsafe { *self.0 as usize }
|
||||||
|
}
|
||||||
|
#[clippy::msrv = "1.58"]
|
||||||
|
fn deref_mut_ptr_cannot_be_const(self) -> usize {
|
||||||
|
unsafe { *self.1 as usize }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -113,3 +113,31 @@ fn drop(&mut self) {
|
|||||||
// Lint this, since it can be dropped in const contexts
|
// Lint this, since it can be dropped in const contexts
|
||||||
// FIXME(effects)
|
// FIXME(effects)
|
||||||
fn d(this: D) {}
|
fn d(this: D) {}
|
||||||
|
|
||||||
|
mod msrv {
|
||||||
|
struct Foo(*const u8, &'static u8);
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
#[clippy::msrv = "1.58"]
|
||||||
|
fn deref_ptr_can_be_const(self) -> usize {
|
||||||
|
//~^ ERROR: this could be a `const fn`
|
||||||
|
unsafe { *self.0 as usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deref_copied_val(self) -> usize {
|
||||||
|
//~^ ERROR: this could be a `const fn`
|
||||||
|
*self.1 as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
union Bar {
|
||||||
|
val: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[clippy::msrv = "1.56"]
|
||||||
|
fn union_access_can_be_const() {
|
||||||
|
//~^ ERROR: this could be a `const fn`
|
||||||
|
let bar = Bar { val: 1 };
|
||||||
|
let _ = unsafe { bar.val };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -102,5 +102,33 @@ LL | | 46
|
|||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: aborting due to 11 previous errors
|
error: this could be a `const fn`
|
||||||
|
--> tests/ui/missing_const_for_fn/could_be_const.rs:122:9
|
||||||
|
|
|
||||||
|
LL | / fn deref_ptr_can_be_const(self) -> usize {
|
||||||
|
LL | |
|
||||||
|
LL | | unsafe { *self.0 as usize }
|
||||||
|
LL | | }
|
||||||
|
| |_________^
|
||||||
|
|
||||||
|
error: this could be a `const fn`
|
||||||
|
--> tests/ui/missing_const_for_fn/could_be_const.rs:127:9
|
||||||
|
|
|
||||||
|
LL | / fn deref_copied_val(self) -> usize {
|
||||||
|
LL | |
|
||||||
|
LL | | *self.1 as usize
|
||||||
|
LL | | }
|
||||||
|
| |_________^
|
||||||
|
|
||||||
|
error: this could be a `const fn`
|
||||||
|
--> tests/ui/missing_const_for_fn/could_be_const.rs:138:5
|
||||||
|
|
|
||||||
|
LL | / fn union_access_can_be_const() {
|
||||||
|
LL | |
|
||||||
|
LL | | let bar = Bar { val: 1 };
|
||||||
|
LL | | let _ = unsafe { bar.val };
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
||||||
|
error: aborting due to 14 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user