1
Fork 0

rustc: Refactor attribute checking to operate on HIR

This'll enable running queries that could be cached and overall be more amenable
to the query infastructure.
This commit is contained in:
Alex Crichton 2018-01-08 13:43:42 -08:00
parent 5f006cebfc
commit 0ecaa67e90
5 changed files with 59 additions and 47 deletions

View file

@ -14,11 +14,10 @@
//! conflicts between multiple such attributes attached to the same //! conflicts between multiple such attributes attached to the same
//! item. //! item.
use session::Session; use ty::TyCtxt;
use syntax::ast; use hir;
use syntax::visit; use hir::intravisit::{self, Visitor, NestedVisitorMap};
use syntax::visit::Visitor;
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
enum Target { enum Target {
@ -30,24 +29,26 @@ enum Target {
} }
impl Target { impl Target {
fn from_item(item: &ast::Item) -> Target { fn from_item(item: &hir::Item) -> Target {
match item.node { match item.node {
ast::ItemKind::Fn(..) => Target::Fn, hir::ItemFn(..) => Target::Fn,
ast::ItemKind::Struct(..) => Target::Struct, hir::ItemStruct(..) => Target::Struct,
ast::ItemKind::Union(..) => Target::Union, hir::ItemUnion(..) => Target::Union,
ast::ItemKind::Enum(..) => Target::Enum, hir::ItemEnum(..) => Target::Enum,
_ => Target::Other, _ => Target::Other,
} }
} }
} }
struct CheckAttrVisitor<'a> { struct CheckAttrVisitor<'a, 'tcx: 'a> {
sess: &'a Session, tcx: TyCtxt<'a, 'tcx, 'tcx>,
} }
impl<'a> CheckAttrVisitor<'a> { impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
/// Check any attribute. /// Check any attribute.
fn check_attributes(&self, item: &ast::Item, target: Target) { fn check_attributes(&self, item: &hir::Item, target: Target) {
self.tcx.target_features_enabled(self.tcx.hir.local_def_id(item.id));
for attr in &item.attrs { for attr in &item.attrs {
if let Some(name) = attr.name() { if let Some(name) = attr.name() {
if name == "inline" { if name == "inline" {
@ -55,20 +56,24 @@ impl<'a> CheckAttrVisitor<'a> {
} }
} }
} }
self.check_repr(item, target); self.check_repr(item, target);
} }
/// Check if an `#[inline]` is applied to a function. /// Check if an `#[inline]` is applied to a function.
fn check_inline(&self, attr: &ast::Attribute, item: &ast::Item, target: Target) { fn check_inline(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) {
if target != Target::Fn { if target != Target::Fn {
struct_span_err!(self.sess, attr.span, E0518, "attribute should be applied to function") struct_span_err!(self.tcx.sess,
attr.span,
E0518,
"attribute should be applied to function")
.span_label(item.span, "not a function") .span_label(item.span, "not a function")
.emit(); .emit();
} }
} }
/// Check if the `#[repr]` attributes on `item` are valid. /// Check if the `#[repr]` attributes on `item` are valid.
fn check_repr(&self, item: &ast::Item, target: Target) { fn check_repr(&self, item: &hir::Item, target: Target) {
// Extract the names of all repr hints, e.g., [foo, bar, align] for: // Extract the names of all repr hints, e.g., [foo, bar, align] for:
// ``` // ```
// #[repr(foo)] // #[repr(foo)]
@ -144,7 +149,7 @@ impl<'a> CheckAttrVisitor<'a> {
} }
_ => continue, _ => continue,
}; };
struct_span_err!(self.sess, hint.span, E0517, struct_span_err!(self.tcx.sess, hint.span, E0517,
"attribute should be applied to {}", allowed_targets) "attribute should be applied to {}", allowed_targets)
.span_label(item.span, format!("not {} {}", article, allowed_targets)) .span_label(item.span, format!("not {} {}", article, allowed_targets))
.emit(); .emit();
@ -154,32 +159,37 @@ impl<'a> CheckAttrVisitor<'a> {
if (int_reprs > 1) if (int_reprs > 1)
|| (is_simd && is_c) || (is_simd && is_c)
|| (int_reprs == 1 && is_c && is_c_like_enum(item)) { || (int_reprs == 1 && is_c && is_c_like_enum(item)) {
// Just point at all repr hints. This is not ideal, but tracking precisely which ones // Just point at all repr hints. This is not ideal, but tracking
// are at fault is a huge hassle. // precisely which ones are at fault is a huge hassle.
let spans: Vec<_> = hints.iter().map(|hint| hint.span).collect(); let spans: Vec<_> = hints.iter().map(|hint| hint.span).collect();
span_warn!(self.sess, spans, E0566, span_warn!(self.tcx.sess, spans, E0566,
"conflicting representation hints"); "conflicting representation hints");
} }
} }
} }
impl<'a> Visitor<'a> for CheckAttrVisitor<'a> { impl<'a, 'tcx> Visitor<'tcx> for CheckAttrVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &'a ast::Item) { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::None
}
fn visit_item(&mut self, item: &'tcx hir::Item) {
let target = Target::from_item(item); let target = Target::from_item(item);
self.check_attributes(item, target); self.check_attributes(item, target);
visit::walk_item(self, item); intravisit::walk_item(self, item);
} }
} }
pub fn check_crate(sess: &Session, krate: &ast::Crate) { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
visit::walk_crate(&mut CheckAttrVisitor { sess: sess }, krate); let mut checker = CheckAttrVisitor { tcx };
tcx.hir.krate().visit_all_item_likes(&mut checker.as_deep_visitor());
} }
fn is_c_like_enum(item: &ast::Item) -> bool { fn is_c_like_enum(item: &hir::Item) -> bool {
if let ast::ItemKind::Enum(ref def, _) = item.node { if let hir::ItemEnum(ref def, _) = item.node {
for variant in &def.variants { for variant in &def.variants {
match variant.node.data { match variant.node.data {
ast::VariantData::Unit(_) => { /* continue */ } hir::VariantData::Unit(_) => { /* continue */ }
_ => { return false; } _ => { return false; }
} }
} }

View file

@ -210,10 +210,6 @@ pub fn compile_input(sess: &Session,
Ok(())); Ok(()));
} }
time(sess.time_passes(), "attribute checking", || {
hir::check_attr::check_crate(sess, &expanded_crate);
});
let opt_crate = if control.keep_ast { let opt_crate = if control.keep_ast {
Some(&expanded_crate) Some(&expanded_crate)
} else { } else {
@ -1038,6 +1034,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(control: &CompileController,
// tcx available. // tcx available.
rustc_incremental::dep_graph_tcx_init(tcx); rustc_incremental::dep_graph_tcx_init(tcx);
time(sess.time_passes(), "attribute checking", || {
hir::check_attr::check_crate(tcx)
});
time(time_passes, time(time_passes,
"stability checking", "stability checking",
|| stability::check_unstable_api_usage(tcx)); || stability::check_unstable_api_usage(tcx));

View file

@ -1,3 +1,5 @@
error[E0601]: main function not found
error[E0518]: attribute should be applied to function error[E0518]: attribute should be applied to function
--> $DIR/issue-43106-gating-of-inline.rs:21:1 --> $DIR/issue-43106-gating-of-inline.rs:21:1
| |
@ -37,7 +39,5 @@ error[E0518]: attribute should be applied to function
35 | #[inline = "2100"] impl S { } 35 | #[inline = "2100"] impl S { }
| ^^^^^^^^^^^^^^^^^^ ---------- not a function | ^^^^^^^^^^^^^^^^^^ ---------- not a function
error[E0601]: main function not found
error: aborting due to 6 previous errors error: aborting due to 6 previous errors

View file

@ -10,6 +10,8 @@
// ignore-arm // ignore-arm
// ignore-aarch64 // ignore-aarch64
// ignore-wasm
// ignore-emscripten
#![feature(target_feature)] #![feature(target_feature)]

View file

@ -1,31 +1,31 @@
warning: #[target_feature = ".."] is deprecated and will eventually be removed, use #[target_feature(enable = "..")] instead warning: #[target_feature = ".."] is deprecated and will eventually be removed, use #[target_feature(enable = "..")] instead
--> $DIR/target-feature-wrong.rs:16:1 --> $DIR/target-feature-wrong.rs:18:1
| |
16 | #[target_feature = "+sse2"] 18 | #[target_feature = "+sse2"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the feature named `foo` is not valid for this target error: the feature named `foo` is not valid for this target
--> $DIR/target-feature-wrong.rs:18:18
|
18 | #[target_feature(enable = "foo")]
| ^^^^^^^^^^^^^^
error: #[target_feature(..)] only accepts sub-keys of `enable` currently
--> $DIR/target-feature-wrong.rs:20:18 --> $DIR/target-feature-wrong.rs:20:18
| |
20 | #[target_feature(bar)] 20 | #[target_feature(enable = "foo")]
| ^^^ | ^^^^^^^^^^^^^^
error: #[target_feature(..)] only accepts sub-keys of `enable` currently error: #[target_feature(..)] only accepts sub-keys of `enable` currently
--> $DIR/target-feature-wrong.rs:22:18 --> $DIR/target-feature-wrong.rs:22:18
| |
22 | #[target_feature(disable = "baz")] 22 | #[target_feature(bar)]
| ^^^
error: #[target_feature(..)] only accepts sub-keys of `enable` currently
--> $DIR/target-feature-wrong.rs:24:18
|
24 | #[target_feature(disable = "baz")]
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
error: #[target_feature(..)] can only be applied to `unsafe` function error: #[target_feature(..)] can only be applied to `unsafe` function
--> $DIR/target-feature-wrong.rs:26:1 --> $DIR/target-feature-wrong.rs:28:1
| |
26 | #[target_feature(enable = "sse2")] 28 | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors error: aborting due to 4 previous errors