Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement basic input validation for built-in attributes #57321

Merged
merged 2 commits into from Jan 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 #57571 <https://github.com/rust-lang/rust/issues/57571>",
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");
}