groundwork for #45009: rustc_dirty/clean enhancements
This commit is contained in:
parent
51cd06170e
commit
ad9b1ed9c2
@ -339,6 +339,25 @@ macro_rules! define_dep_nodes {
|
|||||||
Ok(DepNode::new_no_params(kind))
|
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);
|
||||||
|
)*
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,8 @@
|
|||||||
//! previous revision to compare things to.
|
//! previous revision to compare things to.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::vec::Vec;
|
||||||
use rustc::dep_graph::DepNode;
|
use rustc::dep_graph::DepNode;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
@ -54,6 +56,8 @@ use rustc::ty::TyCtxt;
|
|||||||
const LABEL: &'static str = "label";
|
const LABEL: &'static str = "label";
|
||||||
const CFG: &'static str = "cfg";
|
const CFG: &'static str = "cfg";
|
||||||
|
|
||||||
|
type Labels = HashSet<String>;
|
||||||
|
|
||||||
pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
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
|
// can't add `#[rustc_dirty]` etc without opting in to this feature
|
||||||
if !tcx.sess.features.borrow().rustc_attrs {
|
if !tcx.sess.features.borrow().rustc_attrs {
|
||||||
@ -87,23 +91,46 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
|
||||||
fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode {
|
fn labels(&self, attr: &Attribute) -> Labels {
|
||||||
let def_path_hash = self.tcx.def_path_hash(def_id);
|
|
||||||
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
|
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
|
||||||
if item.check_name(LABEL) {
|
if item.check_name(LABEL) {
|
||||||
let value = expect_associated_value(self.tcx, &item);
|
let value = expect_associated_value(self.tcx, &item);
|
||||||
match DepNode::from_label_string(&value.as_str(), def_path_hash) {
|
return self.resolve_labels(&item, value.as_str().as_ref());
|
||||||
Ok(dep_node) => return dep_node,
|
|
||||||
Err(()) => {
|
|
||||||
self.tcx.sess.span_fatal(
|
|
||||||
item.span,
|
|
||||||
&format!("dep-node label `{}` not recognized", value));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.tcx.sess.span_fatal(attr.span, "no `label` found");
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
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 attr.check_name(ATTR_DIRTY) {
|
||||||
if check_config(self.tcx, attr) {
|
if check_config(self.tcx, attr) {
|
||||||
self.checked_attrs.insert(attr.id);
|
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) {
|
} else if attr.check_name(ATTR_CLEAN) {
|
||||||
if check_config(self.tcx, attr) {
|
if check_config(self.tcx, attr) {
|
||||||
self.checked_attrs.insert(attr.id);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user