rustc: treat impl associated consts like const items for constness.
This commit is contained in:
parent
9b61771ea8
commit
c76a024121
3 changed files with 45 additions and 23 deletions
|
@ -591,15 +591,20 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
Operand::Constant(ref constant) => {
|
||||
if let Literal::Item { def_id, substs } = constant.literal {
|
||||
// Don't peek inside generic (associated) constants.
|
||||
if substs.types().next().is_some() {
|
||||
if let Literal::Item { def_id, substs: _ } = constant.literal {
|
||||
// Don't peek inside trait associated constants.
|
||||
if self.tcx.trait_of_item(def_id).is_some() {
|
||||
self.add_type(constant.ty);
|
||||
} else {
|
||||
let bits = self.tcx.at(constant.span).mir_const_qualif(def_id);
|
||||
|
||||
let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif");
|
||||
self.add(qualif);
|
||||
|
||||
// Just in case the type is more specific than
|
||||
// the definition, e.g. impl associated const
|
||||
// with type parameters, take it into account.
|
||||
self.qualif.restrict(constant.ty, self.tcx, self.param_env);
|
||||
}
|
||||
|
||||
// Let `const fn` transitively have destructors,
|
||||
|
|
|
@ -87,19 +87,14 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Adds the worst effect out of all the values of one type.
|
||||
fn add_type(&mut self, ty: Ty<'gcx>) {
|
||||
if !ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) {
|
||||
self.promotable = false;
|
||||
}
|
||||
|
||||
if ty.needs_drop(self.tcx, self.param_env) {
|
||||
self.promotable = false;
|
||||
}
|
||||
// Returns true iff all the values of the type are promotable.
|
||||
fn type_has_only_promotable_values(&mut self, ty: Ty<'gcx>) -> bool {
|
||||
ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) &&
|
||||
!ty.needs_drop(self.tcx, self.param_env)
|
||||
}
|
||||
|
||||
fn handle_const_fn_call(&mut self, def_id: DefId, ret_ty: Ty<'gcx>) {
|
||||
self.add_type(ret_ty);
|
||||
self.promotable &= self.type_has_only_promotable_values(ret_ty);
|
||||
|
||||
self.promotable &= if let Some(fn_id) = self.tcx.hir.as_local_node_id(def_id) {
|
||||
FnLikeNode::from_node(self.tcx.hir.get(fn_id)).map_or(false, |fn_like| {
|
||||
|
@ -333,20 +328,30 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
|
|||
match def {
|
||||
Def::VariantCtor(..) | Def::StructCtor(..) |
|
||||
Def::Fn(..) | Def::Method(..) => {}
|
||||
Def::AssociatedConst(_) => v.add_type(node_ty),
|
||||
Def::Const(did) => {
|
||||
v.promotable &= if let Some(node_id) = v.tcx.hir.as_local_node_id(did) {
|
||||
match v.tcx.hir.expect_item(node_id).node {
|
||||
hir::ItemConst(_, body) => {
|
||||
|
||||
Def::Const(did) |
|
||||
Def::AssociatedConst(did) => {
|
||||
let promotable = if v.tcx.trait_of_item(did).is_some() {
|
||||
// Don't peek inside trait associated constants.
|
||||
false
|
||||
} else if let Some(node_id) = v.tcx.hir.as_local_node_id(did) {
|
||||
match v.tcx.hir.maybe_body_owned_by(node_id) {
|
||||
Some(body) => {
|
||||
v.visit_nested_body(body);
|
||||
v.tcx.rvalue_promotable_to_static.borrow()[&body.node_id]
|
||||
}
|
||||
_ => false
|
||||
None => false
|
||||
}
|
||||
} else {
|
||||
v.tcx.const_is_rvalue_promotable_to_static(did)
|
||||
};
|
||||
|
||||
// Just in case the type is more specific than the definition,
|
||||
// e.g. impl associated const with type parameters, check it.
|
||||
// Also, trait associated consts are relaxed by this.
|
||||
v.promotable &= promotable || v.type_has_only_promotable_values(node_ty);
|
||||
}
|
||||
|
||||
_ => {
|
||||
v.promotable = false;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,20 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn main() {
|
||||
let x: &'static u32 = &42;
|
||||
let y: &'static Option<u32> = &None;
|
||||
use std::cell::Cell;
|
||||
|
||||
const NONE_CELL_STRING: Option<Cell<String>> = None;
|
||||
|
||||
struct Foo<T>(T);
|
||||
impl<T> Foo<T> {
|
||||
const FOO: Option<Box<T>> = None;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: &'static u32 = &42;
|
||||
let _: &'static Option<u32> = &None;
|
||||
|
||||
// We should be able to peek at consts and see they're None.
|
||||
let _: &'static Option<Cell<String>> = &NONE_CELL_STRING;
|
||||
let _: &'static Option<Box<()>> = &Foo::FOO;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue