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:
parent
5f006cebfc
commit
0ecaa67e90
5 changed files with 59 additions and 47 deletions
|
@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
// ignore-arm
|
// ignore-arm
|
||||||
// ignore-aarch64
|
// ignore-aarch64
|
||||||
|
// ignore-wasm
|
||||||
|
// ignore-emscripten
|
||||||
|
|
||||||
#![feature(target_feature)]
|
#![feature(target_feature)]
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue