Skip to content

Commit 29f2fee

Browse files
authored
Rollup merge of rust-lang#56953 - oli-obk:dead_const, r=petrochenkov
Mark tuple structs as live if their constructors are used fixes rust-lang#56281
2 parents 8cd1817 + 405d8b0 commit 29f2fee

File tree

3 files changed

+51
-43
lines changed

3 files changed

+51
-43
lines changed

src/librustc/hir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2119,7 +2119,7 @@ impl StructField {
21192119
/// Id of the whole enum lives in `Item`.
21202120
///
21212121
/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually
2122-
/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of
2122+
/// used for `Struct`-structs (but still present). Structures don't have an analogue of "Id of
21232123
/// the variant itself" from enum variants.
21242124
/// Id of the whole struct lives in `Item`.
21252125
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]

src/librustc/middle/dead.rs

+38-42
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ use middle::privacy;
2525
use ty::{self, TyCtxt};
2626
use util::nodemap::FxHashSet;
2727

28+
use rustc_data_structures::fx::FxHashMap;
29+
2830
use syntax::{ast, source_map};
2931
use syntax::attr;
3032
use syntax_pos;
@@ -55,12 +57,15 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> {
5557
in_pat: bool,
5658
inherited_pub_visibility: bool,
5759
ignore_variant_stack: Vec<DefId>,
60+
// maps from tuple struct constructors to tuple struct items
61+
struct_constructors: FxHashMap<ast::NodeId, ast::NodeId>,
5862
}
5963

6064
impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
6165
fn check_def_id(&mut self, def_id: DefId) {
6266
if let Some(node_id) = self.tcx.hir().as_local_node_id(def_id) {
63-
if should_explore(self.tcx, node_id) {
67+
if should_explore(self.tcx, node_id) ||
68+
self.struct_constructors.contains_key(&node_id) {
6469
self.worklist.push(node_id);
6570
}
6671
self.live_symbols.insert(node_id);
@@ -137,19 +142,23 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
137142
continue
138143
}
139144

140-
if let Some(ref node) = self.tcx.hir().find(id) {
145+
// in the case of tuple struct constructors we want to check the item, not the generated
146+
// tuple struct constructor function
147+
let id = self.struct_constructors.get(&id).cloned().unwrap_or(id);
148+
149+
if let Some(node) = self.tcx.hir().find(id) {
141150
self.live_symbols.insert(id);
142151
self.visit_node(node);
143152
}
144153
}
145154
}
146155

147-
fn visit_node(&mut self, node: &Node<'tcx>) {
156+
fn visit_node(&mut self, node: Node<'tcx>) {
148157
let had_repr_c = self.repr_has_repr_c;
149158
self.repr_has_repr_c = false;
150159
let had_inherited_pub_visibility = self.inherited_pub_visibility;
151160
self.inherited_pub_visibility = false;
152-
match *node {
161+
match node {
153162
Node::Item(item) => {
154163
match item.node {
155164
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
@@ -337,6 +346,8 @@ struct LifeSeeder<'k, 'tcx: 'k> {
337346
worklist: Vec<ast::NodeId>,
338347
krate: &'k hir::Crate,
339348
tcx: TyCtxt<'k, 'tcx, 'tcx>,
349+
// see `MarkSymbolVisitor::struct_constructors`
350+
struct_constructors: FxHashMap<ast::NodeId, ast::NodeId>,
340351
}
341352

342353
impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
@@ -379,6 +390,9 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
379390
}
380391
}
381392
}
393+
hir::ItemKind::Struct(ref variant_data, _) => {
394+
self.struct_constructors.insert(variant_data.id(), item.id);
395+
}
382396
_ => ()
383397
}
384398
}
@@ -392,11 +406,11 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
392406
}
393407
}
394408

395-
fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
396-
access_levels: &privacy::AccessLevels,
397-
krate: &hir::Crate)
398-
-> Vec<ast::NodeId>
399-
{
409+
fn create_and_seed_worklist<'a, 'tcx>(
410+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
411+
access_levels: &privacy::AccessLevels,
412+
krate: &hir::Crate,
413+
) -> (Vec<ast::NodeId>, FxHashMap<ast::NodeId, ast::NodeId>) {
400414
let worklist = access_levels.map.iter().filter_map(|(&id, level)| {
401415
if level >= &privacy::AccessLevel::Reachable {
402416
Some(id)
@@ -413,17 +427,18 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
413427
worklist,
414428
krate,
415429
tcx,
430+
struct_constructors: Default::default(),
416431
};
417432
krate.visit_all_item_likes(&mut life_seeder);
418433

419-
return life_seeder.worklist;
434+
(life_seeder.worklist, life_seeder.struct_constructors)
420435
}
421436

422437
fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
423438
access_levels: &privacy::AccessLevels,
424439
krate: &hir::Crate)
425440
-> FxHashSet<ast::NodeId> {
426-
let worklist = create_and_seed_worklist(tcx, access_levels, krate);
441+
let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels, krate);
427442
let mut symbol_visitor = MarkSymbolVisitor {
428443
worklist,
429444
tcx,
@@ -433,20 +448,12 @@ fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
433448
in_pat: false,
434449
inherited_pub_visibility: false,
435450
ignore_variant_stack: vec![],
451+
struct_constructors,
436452
};
437453
symbol_visitor.mark_live_symbols();
438454
symbol_visitor.live_symbols
439455
}
440456

441-
fn get_struct_ctor_id(item: &hir::Item) -> Option<ast::NodeId> {
442-
match item.node {
443-
hir::ItemKind::Struct(ref struct_def, _) if !struct_def.is_struct() => {
444-
Some(struct_def.id())
445-
}
446-
_ => None
447-
}
448-
}
449-
450457
struct DeadVisitor<'a, 'tcx: 'a> {
451458
tcx: TyCtxt<'a, 'tcx, 'tcx>,
452459
live_symbols: FxHashSet<ast::NodeId>,
@@ -464,46 +471,35 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
464471
| hir::ItemKind::Union(..) => true,
465472
_ => false
466473
};
467-
let ctor_id = get_struct_ctor_id(item);
468-
should_warn && !self.symbol_is_live(item.id, ctor_id)
474+
should_warn && !self.symbol_is_live(item.id)
469475
}
470476

471477
fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool {
472478
let field_type = self.tcx.type_of(self.tcx.hir().local_def_id(field.id));
473479
!field.is_positional()
474-
&& !self.symbol_is_live(field.id, None)
480+
&& !self.symbol_is_live(field.id)
475481
&& !field_type.is_phantom_data()
476482
&& !has_allow_dead_code_or_lang_attr(self.tcx, field.id, &field.attrs)
477483
}
478484

479485
fn should_warn_about_variant(&mut self, variant: &hir::VariantKind) -> bool {
480-
!self.symbol_is_live(variant.data.id(), None)
486+
!self.symbol_is_live(variant.data.id())
481487
&& !has_allow_dead_code_or_lang_attr(self.tcx,
482488
variant.data.id(),
483489
&variant.attrs)
484490
}
485491

486492
fn should_warn_about_foreign_item(&mut self, fi: &hir::ForeignItem) -> bool {
487-
!self.symbol_is_live(fi.id, None)
493+
!self.symbol_is_live(fi.id)
488494
&& !has_allow_dead_code_or_lang_attr(self.tcx, fi.id, &fi.attrs)
489495
}
490496

491497
// id := node id of an item's definition.
492-
// ctor_id := `Some` if the item is a struct_ctor (tuple struct),
493-
// `None` otherwise.
494-
// If the item is a struct_ctor, then either its `id` or
495-
// `ctor_id` (unwrapped) is in the live_symbols set. More specifically,
496-
// DefMap maps the ExprKind::Path of a struct_ctor to the node referred by
497-
// `ctor_id`. On the other hand, in a statement like
498-
// `type <ident> <generics> = <ty>;` where <ty> refers to a struct_ctor,
499-
// DefMap maps <ty> to `id` instead.
500-
fn symbol_is_live(&mut self,
501-
id: ast::NodeId,
502-
ctor_id: Option<ast::NodeId>)
503-
-> bool {
504-
if self.live_symbols.contains(&id)
505-
|| ctor_id.map_or(false, |ctor| self.live_symbols.contains(&ctor))
506-
{
498+
fn symbol_is_live(
499+
&mut self,
500+
id: ast::NodeId,
501+
) -> bool {
502+
if self.live_symbols.contains(&id) {
507503
return true;
508504
}
509505
// If it's a type whose items are live, then it's live, too.
@@ -611,7 +607,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
611607
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
612608
match impl_item.node {
613609
hir::ImplItemKind::Const(_, body_id) => {
614-
if !self.symbol_is_live(impl_item.id, None) {
610+
if !self.symbol_is_live(impl_item.id) {
615611
self.warn_dead_code(impl_item.id,
616612
impl_item.span,
617613
impl_item.ident.name,
@@ -621,7 +617,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
621617
self.visit_nested_body(body_id)
622618
}
623619
hir::ImplItemKind::Method(_, body_id) => {
624-
if !self.symbol_is_live(impl_item.id, None) {
620+
if !self.symbol_is_live(impl_item.id) {
625621
let span = self.tcx.sess.source_map().def_span(impl_item.span);
626622
self.warn_dead_code(impl_item.id, span, impl_item.ident.name, "method", "used");
627623
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// compile-pass
2+
3+
#![deny(dead_code)]
4+
5+
const LEN: usize = 4;
6+
7+
#[derive(Debug)]
8+
struct Wrapper([u8; LEN]);
9+
10+
fn main() {
11+
println!("{:?}", Wrapper([0, 1, 2, 3]));
12+
}

0 commit comments

Comments
 (0)