Skip to content

Commit c76a024

Browse files
committed
rustc: treat impl associated consts like const items for constness.
1 parent 9b61771 commit c76a024

File tree

3 files changed

+44
-22
lines changed

3 files changed

+44
-22
lines changed

src/librustc_mir/transform/qualify_consts.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -591,15 +591,20 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
591591
}
592592
}
593593
Operand::Constant(ref constant) => {
594-
if let Literal::Item { def_id, substs } = constant.literal {
595-
// Don't peek inside generic (associated) constants.
596-
if substs.types().next().is_some() {
594+
if let Literal::Item { def_id, substs: _ } = constant.literal {
595+
// Don't peek inside trait associated constants.
596+
if self.tcx.trait_of_item(def_id).is_some() {
597597
self.add_type(constant.ty);
598598
} else {
599599
let bits = self.tcx.at(constant.span).mir_const_qualif(def_id);
600600

601601
let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif");
602602
self.add(qualif);
603+
604+
// Just in case the type is more specific than
605+
// the definition, e.g. impl associated const
606+
// with type parameters, take it into account.
607+
self.qualif.restrict(constant.ty, self.tcx, self.param_env);
603608
}
604609

605610
// Let `const fn` transitively have destructors,

src/librustc_passes/consts.rs

+21-16
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,14 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
8787
}
8888
}
8989

90-
// Adds the worst effect out of all the values of one type.
91-
fn add_type(&mut self, ty: Ty<'gcx>) {
92-
if !ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) {
93-
self.promotable = false;
94-
}
95-
96-
if ty.needs_drop(self.tcx, self.param_env) {
97-
self.promotable = false;
98-
}
90+
// Returns true iff all the values of the type are promotable.
91+
fn type_has_only_promotable_values(&mut self, ty: Ty<'gcx>) -> bool {
92+
ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) &&
93+
!ty.needs_drop(self.tcx, self.param_env)
9994
}
10095

10196
fn handle_const_fn_call(&mut self, def_id: DefId, ret_ty: Ty<'gcx>) {
102-
self.add_type(ret_ty);
97+
self.promotable &= self.type_has_only_promotable_values(ret_ty);
10398

10499
self.promotable &= if let Some(fn_id) = self.tcx.hir.as_local_node_id(def_id) {
105100
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
333328
match def {
334329
Def::VariantCtor(..) | Def::StructCtor(..) |
335330
Def::Fn(..) | Def::Method(..) => {}
336-
Def::AssociatedConst(_) => v.add_type(node_ty),
337-
Def::Const(did) => {
338-
v.promotable &= if let Some(node_id) = v.tcx.hir.as_local_node_id(did) {
339-
match v.tcx.hir.expect_item(node_id).node {
340-
hir::ItemConst(_, body) => {
331+
332+
Def::Const(did) |
333+
Def::AssociatedConst(did) => {
334+
let promotable = if v.tcx.trait_of_item(did).is_some() {
335+
// Don't peek inside trait associated constants.
336+
false
337+
} else if let Some(node_id) = v.tcx.hir.as_local_node_id(did) {
338+
match v.tcx.hir.maybe_body_owned_by(node_id) {
339+
Some(body) => {
341340
v.visit_nested_body(body);
342341
v.tcx.rvalue_promotable_to_static.borrow()[&body.node_id]
343342
}
344-
_ => false
343+
None => false
345344
}
346345
} else {
347346
v.tcx.const_is_rvalue_promotable_to_static(did)
348347
};
348+
349+
// Just in case the type is more specific than the definition,
350+
// e.g. impl associated const with type parameters, check it.
351+
// Also, trait associated consts are relaxed by this.
352+
v.promotable &= promotable || v.type_has_only_promotable_values(node_ty);
349353
}
354+
350355
_ => {
351356
v.promotable = false;
352357
}

src/test/run-pass/rvalue-static-promotion.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,20 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#[allow(unused_variables)]
11+
use std::cell::Cell;
12+
13+
const NONE_CELL_STRING: Option<Cell<String>> = None;
14+
15+
struct Foo<T>(T);
16+
impl<T> Foo<T> {
17+
const FOO: Option<Box<T>> = None;
18+
}
19+
1220
fn main() {
13-
let x: &'static u32 = &42;
14-
let y: &'static Option<u32> = &None;
21+
let _: &'static u32 = &42;
22+
let _: &'static Option<u32> = &None;
23+
24+
// We should be able to peek at consts and see they're None.
25+
let _: &'static Option<Cell<String>> = &NONE_CELL_STRING;
26+
let _: &'static Option<Box<()>> = &Foo::FOO;
1527
}

0 commit comments

Comments
 (0)