about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-05-21 17:47:23 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-05-25 11:55:50 -0700
commit609ffa1a890fd6b8b0364cd7b35bf1d45abf82d0 (patch)
treedbd09e2fa625c27c100cb21e6b196c9f45b5ec27 /src/libsyntax
parent02f5786a324c40b2d8b2d0df98456e48fb45d30c (diff)
downloadrust-609ffa1a890fd6b8b0364cd7b35bf1d45abf82d0.tar.gz
rust-609ffa1a890fd6b8b0364cd7b35bf1d45abf82d0.zip
Reword malformed attribute input diagnostics
- Handle empty `cfg_attr` attribute
- Reword empty `derive` attribute error
- Use consistend error message: "malformed `attrname` attribute input"
- Provide suggestions when possible
- Move note/help to label/suggestion
- Use consistent wording "ill-formed" -> "malformed"
- Move diagnostic logic out of parser
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/attr/builtin.rs10
-rw-r--r--src/libsyntax/config.rs16
-rw-r--r--src/libsyntax/ext/derive.rs10
-rw-r--r--src/libsyntax/feature_gate.rs50
4 files changed, 74 insertions, 12 deletions
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index 65ca96afab1..b96f13335b2 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -92,7 +92,15 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
                     }
 
                     diagnostic.map(|d| {
-                        span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute");
+                        struct_span_err!(d, attr.span, E0633, "malformed `unwind` attribute input")
+                            .span_label(attr.span, "invalid argument")
+                            .span_suggestions(
+                                attr.span,
+                                "the allowed arguments are `allowed` and `aborts`",
+                                (vec!["allowed", "aborts"]).into_iter()
+                                    .map(|s| format!("#[unwind({})]", s)),
+                                Applicability::MachineApplicable,
+                            ).emit();
                     });
                 }
             }
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index c82936afa3d..fc413caa428 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -94,6 +94,22 @@ impl<'a> StripUnconfigured<'a> {
         if !attr.check_name(sym::cfg_attr) {
             return vec![attr];
         }
+        if attr.tokens.len() == 0 {
+            self.sess.span_diagnostic
+                .struct_span_err(
+                    attr.span,
+                    "malformed `cfg_attr` attribute input",
+                ).span_suggestion(
+                    attr.span,
+                    "missing condition and attribute",
+                    "#[cfg_attr(condition, attribute, other_attribute, ...)]".to_owned(),
+                    Applicability::HasPlaceholders,
+                ).note("for more information, visit \
+                       <https://doc.rust-lang.org/reference/conditional-compilation.html\
+                       #the-cfg_attr-attribute>")
+                .emit();
+            return Vec::new();
+        }
 
         let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| {
             parser.expect(&token::OpenDelim(token::Paren))?;
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index 6e789c4c708..4db206094d3 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -5,6 +5,7 @@ use crate::ext::base::ExtCtxt;
 use crate::ext::build::AstBuilder;
 use crate::parse::parser::PathStyle;
 use crate::symbol::{Symbol, sym};
+use crate::errors::Applicability;
 
 use syntax_pos::Span;
 
@@ -17,8 +18,13 @@ pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) ->
             return true;
         }
         if !attr.is_meta_item_list() {
-            cx.span_err(attr.span,
-                        "attribute must be of the form `#[derive(Trait1, Trait2, ...)]`");
+            cx.struct_span_err(attr.span, "malformed `derive` attribute input")
+                .span_suggestion(
+                    attr.span,
+                    "missing traits to be derived",
+                    "#[derive(Trait1, Trait2, ...)]".to_owned(),
+                    Applicability::HasPlaceholders,
+                ).emit();
             return false;
         }
 
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 6a049b80aca..b2646efe3e4 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -25,7 +25,7 @@ use crate::parse::{token, ParseSess};
 use crate::symbol::{Symbol, kw, sym};
 use crate::tokenstream::TokenTree;
 
-use errors::{DiagnosticBuilder, Handler};
+use errors::{Applicability, DiagnosticBuilder, Handler};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_target::spec::abi::Abi;
 use syntax_pos::{Span, DUMMY_SP};
@@ -1422,7 +1422,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         Normal,
         template!(
             Word,
-            List: r#"/*opt*/ since = "version", /*opt*/ note = "reason"#,
+            List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
             NameValueStr: "reason"
         ),
         Ungated
@@ -1858,24 +1858,32 @@ impl<'a> PostExpansionVisitor<'a> {
 
         match attr.parse_meta(self.context.parse_sess) {
             Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) {
+                let error_msg = format!("malformed `{}` attribute input", name);
                 let mut msg = "attribute must be of the form ".to_owned();
+                let mut suggestions = vec![];
                 let mut first = true;
                 if template.word {
                     first = false;
-                    msg.push_str(&format!("`#[{}{}]`", name, ""));
+                    let code = format!("#[{}]", name);
+                    msg.push_str(&format!("`{}`", &code));
+                    suggestions.push(code);
                 }
                 if let Some(descr) = template.list {
                     if !first {
                         msg.push_str(" or ");
                     }
                     first = false;
-                    msg.push_str(&format!("`#[{}({})]`", name, descr));
+                    let code = format!("#[{}({})]", name, descr);
+                    msg.push_str(&format!("`{}`", &code));
+                    suggestions.push(code);
                 }
                 if let Some(descr) = template.name_value_str {
                     if !first {
                         msg.push_str(" or ");
                     }
-                    msg.push_str(&format!("`#[{} = \"{}\"]`", name, descr));
+                    let code = format!("#[{} = \"{}\"]", name, descr);
+                    msg.push_str(&format!("`{}`", &code));
+                    suggestions.push(code);
                 }
                 if should_warn(name) {
                     self.context.parse_sess.buffer_lint(
@@ -1885,7 +1893,17 @@ impl<'a> PostExpansionVisitor<'a> {
                         &msg,
                     );
                 } else {
-                    self.context.parse_sess.span_diagnostic.span_err(meta.span, &msg);
+                    self.context.parse_sess.span_diagnostic.struct_span_err(meta.span, &error_msg)
+                        .span_suggestions(
+                            meta.span,
+                            if suggestions.len() == 1 {
+                                "must be of the form"
+                            } else {
+                                "the following are the possible correct uses"
+                            },
+                            suggestions.into_iter(),
+                            Applicability::HasPlaceholders,
+                        ).emit();
                 }
             }
             Err(mut err) => err.emit(),
@@ -2298,6 +2316,8 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
         let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
         if let Some(reason) = reason {
             err.span_note(span, reason);
+        } else {
+            err.span_label(span, "feature has been removed");
         }
         err.emit();
     }
@@ -2379,12 +2399,24 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
             None => continue,
         };
 
+        let bad_input = |span| {
+            struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input")
+        };
+
         for mi in list {
             let name = match mi.ident() {
                 Some(ident) if mi.is_word() => ident.name,
-                _ => {
-                    span_err!(span_handler, mi.span(), E0556,
-                            "malformed feature, expected just one word");
+                Some(ident) => {
+                    bad_input(mi.span()).span_suggestion(
+                        mi.span(),
+                        "expected just one word",
+                        format!("{}", ident.name),
+                        Applicability::MaybeIncorrect,
+                    ).emit();
+                    continue
+                }
+                None => {
+                    bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit();
                     continue
                 }
             };