about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGarrett Berg <googberg@gmail.com>2017-10-02 01:08:13 -0600
committerGarrett Berg <googberg@gmail.com>2017-10-04 07:20:59 -0600
commitad9b1ed9c286d26666b7892145c5cae7f98488bc (patch)
tree3990145e4bce033e11173ccbb7590920ff2075b4
parent51cd06170eccf91a2d93018e939473a8db18da92 (diff)
downloadrust-ad9b1ed9c286d26666b7892145c5cae7f98488bc.tar.gz
rust-ad9b1ed9c286d26666b7892145c5cae7f98488bc.zip
groundwork for #45009: rustc_dirty/clean enhancements
-rw-r--r--src/librustc/dep_graph/dep_node.rs19
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs57
2 files changed, 64 insertions, 12 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 7a78765365d..eef99b0eb28 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -339,6 +339,25 @@ macro_rules! define_dep_nodes {
                     Ok(DepNode::new_no_params(kind))
                 }
             }
+
+            /// Used in testing
+            pub fn has_label_string(label: &str) -> bool {
+                match label {
+                    $(
+                        stringify!($variant) => true,
+                    )*
+                    _ => false,
+                }
+            }
+        }
+
+        /// Contains variant => str representations for constructing
+        /// DepNode groups for tests.
+        #[allow(dead_code, non_upper_case_globals)]
+        pub mod label_strs {
+           $(
+                pub const $variant: &'static str = stringify!($variant);
+            )*
         }
     );
 }
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index a6d39a91863..186759d6219 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -39,6 +39,8 @@
 //! previous revision to compare things to.
 //!
 
+use std::collections::HashSet;
+use std::vec::Vec;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
@@ -54,6 +56,8 @@ use rustc::ty::TyCtxt;
 const LABEL: &'static str = "label";
 const CFG: &'static str = "cfg";
 
+type Labels = HashSet<String>;
+
 pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     // can't add `#[rustc_dirty]` etc without opting in to this feature
     if !tcx.sess.features.borrow().rustc_attrs {
@@ -87,23 +91,46 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
 }
 
 impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
-    fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode {
-        let def_path_hash = self.tcx.def_path_hash(def_id);
+    fn labels(&self, attr: &Attribute) -> Labels {
         for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
             if item.check_name(LABEL) {
                 let value = expect_associated_value(self.tcx, &item);
-                match DepNode::from_label_string(&value.as_str(), def_path_hash) {
-                    Ok(dep_node) => return dep_node,
-                    Err(()) => {
-                        self.tcx.sess.span_fatal(
-                            item.span,
-                            &format!("dep-node label `{}` not recognized", value));
-                    }
+                return self.resolve_labels(&item, value.as_str().as_ref());
+            }
+        }
+        self.tcx.sess.span_fatal(attr.span, "no `label` found");
+    }
+
+    fn resolve_labels(&self, item: &NestedMetaItem, value: &str) -> Labels {
+        let mut out: Labels = HashSet::new();
+        for label in value.split(',') {
+            let label = label.trim();
+            if DepNode::has_label_string(label) {
+                if out.contains(label) {
+                    self.tcx.sess.span_fatal(
+                        item.span,
+                        &format!("dep-node label `{}` is repeated", label));
                 }
+                out.insert(label.to_string());
+            } else {
+                self.tcx.sess.span_fatal(
+                    item.span,
+                    &format!("dep-node label `{}` not recognized", label));
             }
         }
+        out
+    }
 
-        self.tcx.sess.span_fatal(attr.span, "no `label` found");
+    fn dep_nodes(&self, labels: &Labels, def_id: DefId) -> Vec<DepNode> {
+        let mut out = Vec::with_capacity(labels.len());
+        let def_path_hash = self.tcx.def_path_hash(def_id);
+        for label in labels.iter() {
+            match DepNode::from_label_string(label, def_path_hash) {
+                Ok(dep_node) => out.push(dep_node),
+                Err(()) => unreachable!(),
+            }
+        }
+        out
     }
 
     fn dep_node_str(&self, dep_node: &DepNode) -> String {
@@ -150,12 +177,18 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
             if attr.check_name(ATTR_DIRTY) {
                 if check_config(self.tcx, attr) {
                     self.checked_attrs.insert(attr.id);
-                    self.assert_dirty(item_span, self.dep_node(attr, def_id));
+                    let labels = self.labels(attr);
+                    for dep_node in self.dep_nodes(&labels, def_id) {
+                        self.assert_dirty(item_span, dep_node);
+                    }
                 }
             } else if attr.check_name(ATTR_CLEAN) {
                 if check_config(self.tcx, attr) {
                     self.checked_attrs.insert(attr.id);
-                    self.assert_clean(item_span, self.dep_node(attr, def_id));
+                    let labels = self.labels(attr);
+                    for dep_node in self.dep_nodes(&labels, def_id) {
+                        self.assert_clean(item_span, dep_node);
+                    }
                 }
             }
         }