Skip to content

Implement basic input validation for built-in attributes #57321

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

Merged
merged 2 commits into from
Jan 16, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 2 additions & 35 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -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
@@ -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.
@@ -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
@@ -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
Original file line number Diff line number Diff line change
@@ -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.
@@ -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.
13 changes: 7 additions & 6 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
@@ -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,
@@ -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! {
@@ -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,
)
}
2 changes: 0 additions & 2 deletions src/librustc/lint/levels.rs
Original file line number Diff line number Diff line change
@@ -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;
};

3 changes: 2 additions & 1 deletion src/librustc/lint/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
@@ -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,
}
}

13 changes: 3 additions & 10 deletions src/librustc/middle/recursion_limit.rs
Original file line number Diff line number Diff line change
@@ -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;
@@ -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
Original file line number Diff line number Diff line change
@@ -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
26 changes: 10 additions & 16 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
@@ -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)?;
@@ -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 {
@@ -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
81 changes: 4 additions & 77 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
@@ -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};
@@ -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 {
@@ -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,
11 changes: 9 additions & 2 deletions src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
@@ -113,7 +114,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
UnusedImportBraces,
AnonymousParameters,
UnusedDocComment,
BadRepr,
EllipsisInclusiveRangePatterns,
NonCamelCaseTypes,
);
@@ -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.
@@ -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");
}
Loading