From de21c3df0e17674784fe3691e3e5517c0c45cdd3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 1 Oct 2020 18:39:47 +0200 Subject: [PATCH 1/3] Create E0777 error code for "invalid literal in derive" --- compiler/rustc_error_codes/src/error_codes.rs | 1 + .../src/error_codes/E0777.md | 19 +++++++++++++++++++ compiler/rustc_expand/src/proc_macro.rs | 13 +++++++++---- src/test/ui/error-codes/E0777.rs | 4 ++++ src/test/ui/error-codes/E0777.stderr | 11 +++++++++++ 5 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0777.md create mode 100644 src/test/ui/error-codes/E0777.rs create mode 100644 src/test/ui/error-codes/E0777.stderr diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 81f65ac86900f..981b5bb8ba72f 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -459,6 +459,7 @@ E0773: include_str!("./error_codes/E0773.md"), E0774: include_str!("./error_codes/E0774.md"), E0775: include_str!("./error_codes/E0775.md"), E0776: include_str!("./error_codes/E0776.md"), +E0777: include_str!("./error_codes/E0777.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0777.md b/compiler/rustc_error_codes/src/error_codes/E0777.md new file mode 100644 index 0000000000000..8c5c6e28b65c6 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0777.md @@ -0,0 +1,19 @@ +A literal value was used inside `#[derive]`. + +Erroneous code example: + +```compile_fail,E0777 +#[derive("Clone")] // error! +struct Foo; +``` + +Only paths to traits are allowed as argument inside `#[derive]`. You can find +more information about the `#[derive]` attribute in the [Rust Book]. + + +``` +#[derive(Clone)] // ok! +struct Foo; +``` + +[Rust Book]: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 94b3fcf2850d2..320d8fdef4d21 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -5,7 +5,7 @@ use rustc_ast::token; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::{self as ast, *}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, ErrorReported}; +use rustc_errors::{struct_span_err, Applicability, ErrorReported}; use rustc_parse::nt_to_tokenstream; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -182,9 +182,14 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) .filter_map(|nmi| match nmi { NestedMetaItem::Literal(lit) => { error_reported_filter_map = true; - cx.struct_span_err(lit.span, "expected path to a trait, found literal") - .help("for example, write `#[derive(Debug)]` for `Debug`") - .emit(); + struct_span_err!( + cx.sess, + lit.span, + E0777, + "expected path to a trait, found literal", + ) + .help("for example, write `#[derive(Debug)]` for `Debug`") + .emit(); None } NestedMetaItem::MetaItem(mi) => Some(mi), diff --git a/src/test/ui/error-codes/E0777.rs b/src/test/ui/error-codes/E0777.rs new file mode 100644 index 0000000000000..ab633e4f53534 --- /dev/null +++ b/src/test/ui/error-codes/E0777.rs @@ -0,0 +1,4 @@ +#[derive("Clone")] //~ ERROR E0777 +struct Foo; + +fn main() {} diff --git a/src/test/ui/error-codes/E0777.stderr b/src/test/ui/error-codes/E0777.stderr new file mode 100644 index 0000000000000..b356ea508f4f3 --- /dev/null +++ b/src/test/ui/error-codes/E0777.stderr @@ -0,0 +1,11 @@ +error[E0777]: expected path to a trait, found literal + --> $DIR/E0777.rs:1:10 + | +LL | #[derive("Clone")] + | ^^^^^^^ + | + = help: for example, write `#[derive(Debug)]` for `Debug` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0777`. From 8b7aeefede5fafacf43edf9e24b1b62b6df34ba5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 1 Oct 2020 20:15:01 +0200 Subject: [PATCH 2/3] Import struct_span_err macro instead of prepending it --- compiler/rustc_expand/src/expand.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index e5cfb866938e5..c6287693dc9e6 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -18,7 +18,7 @@ use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::{struct_span_err, Applicability, PResult}; use rustc_feature::Features; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; @@ -542,7 +542,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) { let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive); let span = attr.map_or(item.span(), |attr| attr.span); - let mut err = rustc_errors::struct_span_err!( + let mut err = struct_span_err!( self.cx.sess, span, E0774, From d1d94ba026eda45a2b998d68524c14929604c748 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 Oct 2020 13:52:03 +0200 Subject: [PATCH 3/3] Improve E0777 help message --- compiler/rustc_expand/src/proc_macro.rs | 17 +++++++++++++---- src/test/ui/error-codes/E0777.rs | 3 +++ src/test/ui/error-codes/E0777.stderr | 12 +++++++++++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 320d8fdef4d21..4c95f19b96dc6 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -6,6 +6,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::{self as ast, *}; use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability, ErrorReported}; +use rustc_lexer::is_ident; use rustc_parse::nt_to_tokenstream; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -182,14 +183,22 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) .filter_map(|nmi| match nmi { NestedMetaItem::Literal(lit) => { error_reported_filter_map = true; - struct_span_err!( + let mut err = struct_span_err!( cx.sess, lit.span, E0777, "expected path to a trait, found literal", - ) - .help("for example, write `#[derive(Debug)]` for `Debug`") - .emit(); + ); + let token = lit.token.to_string(); + if token.starts_with('"') + && token.len() > 2 + && is_ident(&token[1..token.len() - 1]) + { + err.help(&format!("try using `#[derive({})]`", &token[1..token.len() - 1])); + } else { + err.help("for example, write `#[derive(Debug)]` for `Debug`"); + } + err.emit(); None } NestedMetaItem::MetaItem(mi) => Some(mi), diff --git a/src/test/ui/error-codes/E0777.rs b/src/test/ui/error-codes/E0777.rs index ab633e4f53534..ff70f73686665 100644 --- a/src/test/ui/error-codes/E0777.rs +++ b/src/test/ui/error-codes/E0777.rs @@ -1,4 +1,7 @@ #[derive("Clone")] //~ ERROR E0777 +#[derive("Clone +")] +//~^^ ERROR E0777 struct Foo; fn main() {} diff --git a/src/test/ui/error-codes/E0777.stderr b/src/test/ui/error-codes/E0777.stderr index b356ea508f4f3..ea73c58993e2b 100644 --- a/src/test/ui/error-codes/E0777.stderr +++ b/src/test/ui/error-codes/E0777.stderr @@ -4,8 +4,18 @@ error[E0777]: expected path to a trait, found literal LL | #[derive("Clone")] | ^^^^^^^ | + = help: try using `#[derive(Clone)]` + +error[E0777]: expected path to a trait, found literal + --> $DIR/E0777.rs:2:10 + | +LL | #[derive("Clone + | __________^ +LL | | ")] + | |_^ + | = help: for example, write `#[derive(Debug)]` for `Debug` -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0777`.