Skip to content

Commit f810d3e

Browse files
committed
Add support for registering attributes with rustc in plugins
This lets plugin authors opt attributes out of the `custom_attribute` and `unused_attribute` checks.
1 parent fc45fd9 commit f810d3e

File tree

5 files changed

+58
-7
lines changed

5 files changed

+58
-7
lines changed

src/librustc/plugin/registry.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use syntax::codemap::Span;
2020
use syntax::parse::token;
2121
use syntax::ptr::P;
2222
use syntax::ast;
23+
use syntax::feature_gate::AttributeType;
2324

2425
use std::collections::HashMap;
2526
use std::borrow::ToOwned;
@@ -54,6 +55,9 @@ pub struct Registry<'a> {
5455

5556
#[doc(hidden)]
5657
pub llvm_passes: Vec<String>,
58+
59+
#[doc(hidden)]
60+
pub attributes: Vec<(String, AttributeType)>,
5761
}
5862

5963
impl<'a> Registry<'a> {
@@ -67,6 +71,7 @@ impl<'a> Registry<'a> {
6771
lint_passes: vec!(),
6872
lint_groups: HashMap::new(),
6973
llvm_passes: vec!(),
74+
attributes: vec!(),
7075
}
7176
}
7277

@@ -130,4 +135,22 @@ impl<'a> Registry<'a> {
130135
pub fn register_llvm_pass(&mut self, name: &str) {
131136
self.llvm_passes.push(name.to_owned());
132137
}
138+
139+
140+
/// Register an attribute with an attribute type
141+
///
142+
/// Registered attributes will bypass the `custom_attribute` feature gate
143+
///
144+
/// `Whitelisted` attributes will additionally not trigger the `unused_attribute`
145+
/// lint
146+
///
147+
/// `CrateLevel` attributes will not be allowed on anything other than a crate
148+
pub fn register_attribute(&mut self, name: String, ty: AttributeType) {
149+
if let AttributeType::Gated(..) = ty {
150+
self.sess.err("plugin tried to register a gated attribute. \
151+
Only `Normal`, `Whitelisted`, and `CrateLevel` \
152+
attributes are allowed");
153+
}
154+
self.attributes.push((name, ty));
155+
}
133156
}

src/librustc/session/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use syntax::parse;
2323
use syntax::parse::token;
2424
use syntax::parse::ParseSess;
2525
use syntax::{ast, codemap};
26+
use syntax::feature_gate::AttributeType;
2627

2728
use rustc_back::target::Target;
2829

@@ -54,6 +55,7 @@ pub struct Session {
5455
pub lint_store: RefCell<lint::LintStore>,
5556
pub lints: RefCell<NodeMap<Vec<(lint::LintId, codemap::Span, String)>>>,
5657
pub plugin_llvm_passes: RefCell<Vec<String>>,
58+
pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
5759
pub crate_types: RefCell<Vec<config::CrateType>>,
5860
pub crate_metadata: RefCell<Vec<String>>,
5961
pub features: RefCell<feature_gate::Features>,
@@ -416,6 +418,7 @@ pub fn build_session_(sopts: config::Options,
416418
lint_store: RefCell::new(lint::LintStore::new()),
417419
lints: RefCell::new(NodeMap()),
418420
plugin_llvm_passes: RefCell::new(Vec::new()),
421+
plugin_attributes: RefCell::new(Vec::new()),
419422
crate_types: RefCell::new(Vec::new()),
420423
crate_metadata: RefCell::new(Vec::new()),
421424
delayed_span_bug: RefCell::new(None),

src/librustc_driver/driver.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,8 @@ pub fn phase_2_configure_and_expand(sess: &Session,
444444
}
445445
});
446446

447-
let Registry { syntax_exts, lint_passes, lint_groups, llvm_passes, .. } = registry;
447+
let Registry { syntax_exts, lint_passes, lint_groups,
448+
llvm_passes, attributes, .. } = registry;
448449

449450
{
450451
let mut ls = sess.lint_store.borrow_mut();
@@ -457,6 +458,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
457458
}
458459

459460
*sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
461+
*sess.plugin_attributes.borrow_mut() = attributes.clone();
460462
}
461463

462464
// Lint plugins are registered; now we can process command line flags.
@@ -511,7 +513,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
511513
let features =
512514
syntax::feature_gate::check_crate(sess.codemap(),
513515
&sess.parse_sess.span_diagnostic,
514-
&krate);
516+
&krate, &attributes);
515517
*sess.features.borrow_mut() = features;
516518
sess.abort_if_errors();
517519
});
@@ -541,7 +543,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
541543
let features =
542544
syntax::feature_gate::check_crate(sess.codemap(),
543545
&sess.parse_sess.span_diagnostic,
544-
&krate);
546+
&krate, &attributes);
545547
*sess.features.borrow_mut() = features;
546548
sess.abort_if_errors();
547549
});

src/librustc_lint/builtin.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,9 +641,22 @@ impl LintPass for UnusedAttributes {
641641
}
642642
}
643643

644+
let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
645+
for &(ref name, ty) in plugin_attributes.iter() {
646+
match ty {
647+
AttributeType::Whitelisted if attr.check_name(&*name) => {
648+
break;
649+
},
650+
_ => ()
651+
}
652+
}
653+
644654
if !attr::is_used(attr) {
645655
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
646-
if KNOWN_ATTRIBUTES.contains(&(&attr.name(), AttributeType::CrateLevel)) {
656+
if KNOWN_ATTRIBUTES.contains(&(&attr.name(), AttributeType::CrateLevel)) ||
657+
plugin_attributes.iter()
658+
.find(|&&(ref x, t)| &*attr.name() == &*x && AttributeType::CrateLevel == t)
659+
.is_some() {
647660
let msg = match attr.node.style {
648661
ast::AttrOuter => "crate-level attribute should be an inner \
649662
attribute: add an exclamation mark: #![foo]",

src/libsyntax/feature_gate.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ struct Context<'a> {
359359
features: Vec<&'static str>,
360360
span_handler: &'a SpanHandler,
361361
cm: &'a CodeMap,
362+
plugin_attributes: &'a [(String, AttributeType)],
362363
}
363364

364365
impl<'a> Context<'a> {
@@ -385,6 +386,13 @@ impl<'a> Context<'a> {
385386
return;
386387
}
387388
}
389+
for &(ref n, ref ty) in self.plugin_attributes.iter() {
390+
if &*n == name {
391+
// Plugins can't gate attributes, so we don't check for it
392+
debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
393+
return;
394+
}
395+
}
388396
if name.starts_with("rustc_") {
389397
self.gate_feature("rustc_attrs", attr.span,
390398
"unless otherwise specified, attributes \
@@ -685,6 +693,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
685693

686694
fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
687695
krate: &ast::Crate,
696+
plugin_attributes: &[(String, AttributeType)],
688697
check: F)
689698
-> Features
690699
where F: FnOnce(&mut Context, &ast::Crate)
@@ -693,6 +702,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
693702
features: Vec::new(),
694703
span_handler: span_handler,
695704
cm: cm,
705+
plugin_attributes: plugin_attributes,
696706
};
697707

698708
let mut accepted_features = Vec::new();
@@ -765,14 +775,14 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
765775

766776
pub fn check_crate_macros(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate)
767777
-> Features {
768-
check_crate_inner(cm, span_handler, krate,
778+
check_crate_inner(cm, span_handler, krate, &[] as &'static [_],
769779
|ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate))
770780
}
771781

772-
pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate)
782+
pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate, plugin_attributes: &[(String, AttributeType)])
773783
-> Features
774784
{
775-
check_crate_inner(cm, span_handler, krate,
785+
check_crate_inner(cm, span_handler, krate, plugin_attributes,
776786
|ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx },
777787
krate))
778788
}

0 commit comments

Comments
 (0)