Skip to content

Commit

Permalink
Implement basic input validation for built-in attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Jan 13, 2019
1 parent 75a369c commit 41c6599
Show file tree
Hide file tree
Showing 106 changed files with 1,391 additions and 1,625 deletions.
37 changes: 2 additions & 35 deletions src/librustc/diagnostics.rs
Expand Up @@ -1180,27 +1180,6 @@ fn main() {
```
"##,

E0296: r##"
This error indicates that the given recursion limit could not be parsed. Ensure
that the value provided is a positive integer between quotes.
Erroneous code example:
```compile_fail,E0296
#![recursion_limit]
fn main() {}
```
And a working example:
```
#![recursion_limit="1000"]
fn main() {}
```
"##,

E0308: r##"
This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
Expand Down Expand Up @@ -2093,20 +2072,6 @@ trait Foo { }
```
"##,

E0702: r##"
This error indicates that a `#[non_exhaustive]` attribute had a value. The
`#[non_exhaustive]` should be empty.
Examples of erroneous code:
```compile_fail,E0702
# #![feature(non_exhaustive)]
#[non_exhaustive(anything)]
struct Foo;
```
"##,

E0718: r##"
This error indicates that a `#[lang = ".."]` attribute was placed
on the wrong type of item.
Expand Down Expand Up @@ -2138,6 +2103,7 @@ register_diagnostics! {
E0280, // requirement is not satisfied
E0284, // cannot resolve type
// E0285, // overflow evaluation builtin bounds
// E0296, // replaced with a generic attribute input check
// E0300, // unexpanded macro
// E0304, // expected signed integer constant
// E0305, // expected constant
Expand Down Expand Up @@ -2180,4 +2146,5 @@ register_diagnostics! {
E0709, // multiple different lifetimes used in arguments of `async fn`
E0710, // an unknown tool name found in scoped lint
E0711, // a feature has been declared with conflicting stability attributes
// E0702, // replaced with a generic attribute input check
}
15 changes: 0 additions & 15 deletions src/librustc/hir/check_attr.rs
Expand Up @@ -137,15 +137,6 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
return;
}
}

if attr.meta_item_list().is_some() || attr.value_str().is_some() {
struct_span_err!(self.tcx.sess,
attr.span,
E0702,
"attribute should be empty")
.span_label(item.span, "not empty")
.emit();
}
}

/// Check if the `#[marker]` attribute on an `item` is valid.
Expand All @@ -160,12 +151,6 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
return;
}
}

if !attr.is_word() {
self.tcx.sess
.struct_span_err(attr.span, "attribute should be empty")
.emit();
}
}

/// Check if the `#[repr]` attributes on `item` are valid.
Expand Down
13 changes: 7 additions & 6 deletions src/librustc/lint/builtin.rs
Expand Up @@ -204,12 +204,6 @@ declare_lint! {
"trait-object types were treated as different depending on marker-trait order"
}

declare_lint! {
pub BAD_REPR,
Warn,
"detects incorrect use of `repr` attribute"
}

declare_lint! {
pub DEPRECATED,
Warn,
Expand Down Expand Up @@ -359,6 +353,12 @@ pub mod parser {
Allow,
"detects the use of `?` as a macro separator"
}

declare_lint! {
pub ILL_FORMED_ATTRIBUTE_INPUT,
Warn,
"ill-formed attribute inputs that were previously accepted and used in practice"
}
}

declare_lint! {
Expand Down Expand Up @@ -431,6 +431,7 @@ impl LintPass for HardwiredLints {
MACRO_USE_EXTERN_CRATE,
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
parser::QUESTION_MARK_MACRO_SEP,
parser::ILL_FORMED_ATTRIBUTE_INPUT,
DEPRECATED_IN_FUTURE,
)
}
Expand Down
2 changes: 0 additions & 2 deletions src/librustc/lint/levels.rs
Expand Up @@ -204,8 +204,6 @@ impl<'a> LintLevelsBuilder<'a> {
let mut metas = if let Some(metas) = meta.meta_item_list() {
metas
} else {
let mut err = bad_attr(meta.span);
err.emit();
continue;
};

Expand Down
3 changes: 2 additions & 1 deletion src/librustc/lint/mod.rs
Expand Up @@ -28,7 +28,7 @@ use hir::def_id::{CrateNum, LOCAL_CRATE};
use hir::intravisit;
use hir;
use lint::builtin::BuiltinLintDiagnostics;
use lint::builtin::parser::QUESTION_MARK_MACRO_SEP;
use lint::builtin::parser::{QUESTION_MARK_MACRO_SEP, ILL_FORMED_ATTRIBUTE_INPUT};
use session::{Session, DiagnosticMessageId};
use std::{hash, ptr};
use syntax::ast;
Expand Down Expand Up @@ -82,6 +82,7 @@ impl Lint {
pub fn from_parser_lint_id(lint_id: BufferedEarlyLintId) -> &'static Self {
match lint_id {
BufferedEarlyLintId::QuestionMarkMacroSep => QUESTION_MARK_MACRO_SEP,
BufferedEarlyLintId::IllFormedAttributeInput => ILL_FORMED_ATTRIBUTE_INPUT,
}
}

Expand Down
13 changes: 3 additions & 10 deletions src/librustc/middle/recursion_limit.rs
Expand Up @@ -11,14 +11,11 @@ use syntax::ast;
use rustc_data_structures::sync::Once;

pub fn update_limits(sess: &Session, krate: &ast::Crate) {
update_limit(sess, krate, &sess.recursion_limit, "recursion_limit",
"recursion limit", 64);
update_limit(sess, krate, &sess.type_length_limit, "type_length_limit",
"type length limit", 1048576);
update_limit(krate, &sess.recursion_limit, "recursion_limit", 64);
update_limit(krate, &sess.type_length_limit, "type_length_limit", 1048576);
}

fn update_limit(sess: &Session, krate: &ast::Crate, limit: &Once<usize>,
name: &str, description: &str, default: usize) {
fn update_limit(krate: &ast::Crate, limit: &Once<usize>, name: &str, default: usize) {
for attr in &krate.attrs {
if !attr.check_name(name) {
continue;
Expand All @@ -30,10 +27,6 @@ fn update_limit(sess: &Session, krate: &ast::Crate, limit: &Once<usize>,
return;
}
}

span_err!(sess, attr.span, E0296,
"malformed {} attribute, expected #![{}=\"N\"]",
description, name);
}
limit.set(default);
}
5 changes: 1 addition & 4 deletions src/librustc/traits/on_unimplemented.rs
Expand Up @@ -157,10 +157,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
note: None,
}))
} else {
return Err(parse_error(tcx, attr.span,
"`#[rustc_on_unimplemented]` requires a value",
"value required here",
Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#)));
return Err(ErrorReported);
};
debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result);
result
Expand Down
26 changes: 10 additions & 16 deletions src/librustc_driver/driver.rs
Expand Up @@ -1070,15 +1070,6 @@ where
)
});

// Add all buffered lints from the `ParseSess` to the `Session`.
sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
info!("{} parse sess buffered_lints", buffered_lints.len());
for BufferedEarlyLint{id, span, msg, lint_id} in buffered_lints.drain(..) {
let lint = lint::Lint::from_parser_lint_id(lint_id);
sess.buffer_lint(lint, id, span, &msg);
}
});

// Done with macro expansion!

after_expand(&krate)?;
Expand Down Expand Up @@ -1114,6 +1105,15 @@ where
);
});

// Add all buffered lints from the `ParseSess` to the `Session`.
sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
info!("{} parse sess buffered_lints", buffered_lints.len());
for BufferedEarlyLint{id, span, msg, lint_id} in buffered_lints.drain(..) {
let lint = lint::Lint::from_parser_lint_id(lint_id);
sess.buffer_lint(lint, id, span, &msg);
}
});

// Lower ast -> hir.
// First, we need to collect the dep_graph.
let dep_graph = match future_dep_graph {
Expand Down Expand Up @@ -1526,13 +1526,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
}
None
}
None => {
session
.struct_span_err(a.span, "`crate_type` requires a value")
.note("for example: `#![crate_type=\"lib\"]`")
.emit();
None
}
None => None
}
} else {
None
Expand Down
81 changes: 4 additions & 77 deletions src/librustc_lint/builtin.rs
Expand Up @@ -35,7 +35,8 @@ use syntax::ast::Expr;
use syntax::attr;
use syntax::source_map::Spanned;
use syntax::edition::Edition;
use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes};
use syntax::feature_gate::{AttributeGate, AttributeTemplate, AttributeType};
use syntax::feature_gate::{Stability, deprecated_attributes};
use syntax_pos::{BytePos, Span, SyntaxContext};
use syntax::symbol::keywords;
use syntax::errors::{Applicability, DiagnosticBuilder};
Expand Down Expand Up @@ -682,86 +683,12 @@ impl EarlyLintPass for AnonymousParameters {
}
}

/// Checks for incorrect use of `repr` attributes.
#[derive(Clone)]
pub struct BadRepr;

impl LintPass for BadRepr {
fn get_lints(&self) -> LintArray {
lint_array!()
}
}

impl EarlyLintPass for BadRepr {
fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) {
if attr.name() == "repr" {
let list = attr.meta_item_list();

let repr_str = |lit: &str| { format!("#[repr({})]", lit) };

// Emit warnings with `repr` either has a literal assignment (`#[repr = "C"]`) or
// no hints (``#[repr]`)
let has_hints = list.as_ref().map(|ref list| !list.is_empty()).unwrap_or(false);
if !has_hints {
let mut suggested = false;
let mut warn = if let Some(ref lit) = attr.value_str() {
// avoid warning about empty `repr` on `#[repr = "foo"]`
let mut warn = cx.struct_span_lint(
BAD_REPR,
attr.span,
"`repr` attribute isn't configurable with a literal",
);
match lit.to_string().as_ref() {
| "C" | "packed" | "rust" | "transparent"
| "u8" | "u16" | "u32" | "u64" | "u128" | "usize"
| "i8" | "i16" | "i32" | "i64" | "i128" | "isize" => {
// if the literal could have been a valid `repr` arg,
// suggest the correct syntax
warn.span_suggestion_with_applicability(
attr.span,
"give `repr` a hint",
repr_str(&lit.as_str()),
Applicability::MachineApplicable
);
suggested = true;
}
_ => { // the literal wasn't a valid `repr` arg
warn.span_label(attr.span, "needs a hint");
}
};
warn
} else {
let mut warn = cx.struct_span_lint(
BAD_REPR,
attr.span,
"`repr` attribute must have a hint",
);
warn.span_label(attr.span, "needs a hint");
warn
};
if !suggested {
warn.help(&format!(
"valid hints include `{}`, `{}`, `{}` and `{}`",
repr_str("C"),
repr_str("packed"),
repr_str("rust"),
repr_str("transparent"),
));
warn.note("for more information, visit \
<https://doc.rust-lang.org/reference/type-layout.html>");
}
warn.emit();
}
}
}
}

/// Checks for use of attributes which have been deprecated.
#[derive(Clone)]
pub struct DeprecatedAttr {
// This is not free to compute, so we want to keep it around, rather than
// compute it for every attribute.
depr_attrs: Vec<&'static (&'static str, AttributeType, AttributeGate)>,
depr_attrs: Vec<&'static (&'static str, AttributeType, AttributeTemplate, AttributeGate)>,
}

impl DeprecatedAttr {
Expand All @@ -780,7 +707,7 @@ impl LintPass for DeprecatedAttr {

impl EarlyLintPass for DeprecatedAttr {
fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) {
for &&(n, _, ref g) in &self.depr_attrs {
for &&(n, _, _, ref g) in &self.depr_attrs {
if attr.name() == n {
if let &AttributeGate::Gated(Stability::Deprecated(link, suggestion),
ref name,
Expand Down
11 changes: 9 additions & 2 deletions src/librustc_lint/lib.rs
Expand Up @@ -48,7 +48,8 @@ use rustc::lint::builtin::{
INTRA_DOC_LINK_RESOLUTION_FAILURE,
MISSING_DOC_CODE_EXAMPLES,
PRIVATE_DOC_TESTS,
parser::QUESTION_MARK_MACRO_SEP
parser::QUESTION_MARK_MACRO_SEP,
parser::ILL_FORMED_ATTRIBUTE_INPUT,
};
use rustc::session;
use rustc::util;
Expand Down Expand Up @@ -113,7 +114,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
UnusedImportBraces,
AnonymousParameters,
UnusedDocComment,
BadRepr,
EllipsisInclusiveRangePatterns,
NonCamelCaseTypes,
);
Expand Down Expand Up @@ -336,6 +336,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>",
edition: None,
},
FutureIncompatibleInfo {
id: LintId::of(ILL_FORMED_ATTRIBUTE_INPUT),
reference: "issue #57321 <https://github.com/rust-lang/rust/issues/57321>",
edition: None,
},
]);

// Register renamed and removed lints.
Expand Down Expand Up @@ -385,4 +390,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
"no longer a warning, #[no_mangle] functions always exported");
store.register_removed("private_no_mangle_statics",
"no longer a warning, #[no_mangle] statics always exported");
store.register_removed("bad_repr",
"replaced with a generic attribute input check");
}

0 comments on commit 41c6599

Please sign in to comment.