diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 8f672bb7d6529..8c53094b62496 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -2,6 +2,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use rustc_ast::ptr::P; +use rustc_ast::walk_list; use rustc_ast::EnumDef; use rustc_ast::VariantData; use rustc_ast::{Expr, MetaItem}; @@ -19,6 +20,8 @@ pub fn expand_deriving_default( item: &Annotatable, push: &mut dyn FnMut(Annotatable), ) { + item.visit_with(&mut DetectNonVariantDefaultAttr { cx }); + let inline = cx.meta_word(span, sym::inline); let attrs = vec![cx.attribute(inline)]; let trait_def = TraitDef { @@ -184,9 +187,12 @@ fn extract_default_variant<'a>( }; if !matches!(variant.data, VariantData::Unit(..)) { - cx.struct_span_err(variant.ident.span, "`#[default]` may only be used on unit variants") - .help("consider a manual implementation of `Default`") - .emit(); + cx.struct_span_err( + variant.ident.span, + "the `#[default]` attribute may only be used on unit enum variants", + ) + .help("consider a manual implementation of `Default`") + .emit(); return Err(()); } @@ -253,3 +259,31 @@ fn validate_default_attribute( } Ok(()) } + +struct DetectNonVariantDefaultAttr<'a, 'b> { + cx: &'a ExtCtxt<'b>, +} + +impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> { + fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) { + if attr.has_name(kw::Default) { + self.cx + .struct_span_err( + attr.span, + "the `#[default]` attribute may only be used on unit enum variants", + ) + .emit(); + } + + rustc_ast::visit::walk_attribute(self, attr); + } + fn visit_variant(&mut self, v: &'a rustc_ast::Variant) { + self.visit_ident(v.ident); + self.visit_vis(&v.vis); + self.visit_variant_data(&v.data); + walk_list!(self, visit_anon_const, &v.disr_expr); + for attr in &v.attrs { + rustc_ast::visit::walk_attribute(self, attr); + } + } +} diff --git a/src/test/ui/macros/macros-nonfatal-errors.rs b/src/test/ui/macros/macros-nonfatal-errors.rs index bb5f4d089bc1f..faacc6f081d31 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.rs +++ b/src/test/ui/macros/macros-nonfatal-errors.rs @@ -5,8 +5,40 @@ #![feature(asm, llvm_asm)] #![feature(trace_macros, concat_idents)] +#![feature(stmt_expr_attributes, arbitrary_enum_discriminant)] #![feature(derive_default_enum)] +#[derive(Default)] +struct DefaultInnerAttrStruct { + #[default] //~ ERROR the `#[default]` attribute may only be used on unit enum variants + foo: (), +} + +#[derive(Default)] +struct DefaultInnerAttrTupleStruct(#[default] ()); +//~^ ERROR the `#[default]` attribute may only be used on unit enum variants + +#[derive(Default)] +#[default] //~ ERROR the `#[default]` attribute may only be used on unit enum variants +struct DefaultOuterAttrStruct {} + +#[derive(Default)] +#[default] //~ ERROR the `#[default]` attribute may only be used on unit enum variants +enum DefaultOuterAttrEnum { + #[default] + Foo, +} + +#[rustfmt::skip] // needs some work to handle this case +#[repr(u8)] +#[derive(Default)] +enum AttrOnInnerExpression { + Foo = #[default] 0, //~ ERROR the `#[default]` attribute may only be used on unit enum variants + Bar([u8; #[default] 1]), //~ ERROR the `#[default]` attribute may only be used on unit enum variants + #[default] + Baz, +} + #[derive(Default)] //~ ERROR no default declared enum NoDeclaredDefault { Foo, @@ -50,7 +82,7 @@ enum ManyDefaultAttrs { #[derive(Default)] enum DefaultHasFields { #[default] - Foo {}, //~ ERROR `#[default]` may only be used on unit variants + Foo {}, //~ ERROR the `#[default]` attribute may only be used on unit enum variants Bar, } diff --git a/src/test/ui/macros/macros-nonfatal-errors.stderr b/src/test/ui/macros/macros-nonfatal-errors.stderr index 4bb5e9b816950..e0ed8522bf652 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.stderr +++ b/src/test/ui/macros/macros-nonfatal-errors.stderr @@ -1,5 +1,41 @@ +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:13:5 + | +LL | #[default] + | ^^^^^^^^^^ + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:18:36 + | +LL | struct DefaultInnerAttrTupleStruct(#[default] ()); + | ^^^^^^^^^^ + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:22:1 + | +LL | #[default] + | ^^^^^^^^^^ + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:26:1 + | +LL | #[default] + | ^^^^^^^^^^ + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:36:11 + | +LL | Foo = #[default] 0, + | ^^^^^^^^^^ + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:37:14 + | +LL | Bar([u8; #[default] 1]), + | ^^^^^^^^^^ + error: no default declared - --> $DIR/macros-nonfatal-errors.rs:10:10 + --> $DIR/macros-nonfatal-errors.rs:42:10 | LL | #[derive(Default)] | ^^^^^^^ @@ -8,7 +44,7 @@ LL | #[derive(Default)] = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) error: multiple declared defaults - --> $DIR/macros-nonfatal-errors.rs:16:10 + --> $DIR/macros-nonfatal-errors.rs:48:10 | LL | #[derive(Default)] | ^^^^^^^ @@ -26,7 +62,7 @@ LL | Baz, = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) error: `#[default]` attribute does not accept a value - --> $DIR/macros-nonfatal-errors.rs:28:5 + --> $DIR/macros-nonfatal-errors.rs:60:5 | LL | #[default = 1] | ^^^^^^^^^^^^^^ @@ -34,7 +70,7 @@ LL | #[default = 1] = help: try using `#[default]` error: multiple `#[default]` attributes - --> $DIR/macros-nonfatal-errors.rs:36:5 + --> $DIR/macros-nonfatal-errors.rs:68:5 | LL | #[default] | ---------- `#[default]` used here @@ -45,13 +81,13 @@ LL | Foo, | = note: only one `#[default]` attribute is needed help: try removing this - --> $DIR/macros-nonfatal-errors.rs:35:5 + --> $DIR/macros-nonfatal-errors.rs:67:5 | LL | #[default] | ^^^^^^^^^^ error: multiple `#[default]` attributes - --> $DIR/macros-nonfatal-errors.rs:46:5 + --> $DIR/macros-nonfatal-errors.rs:78:5 | LL | #[default] | ---------- `#[default]` used here @@ -63,7 +99,7 @@ LL | Foo, | = note: only one `#[default]` attribute is needed help: try removing these - --> $DIR/macros-nonfatal-errors.rs:43:5 + --> $DIR/macros-nonfatal-errors.rs:75:5 | LL | #[default] | ^^^^^^^^^^ @@ -72,8 +108,8 @@ LL | #[default] LL | #[default] | ^^^^^^^^^^ -error: `#[default]` may only be used on unit variants - --> $DIR/macros-nonfatal-errors.rs:53:5 +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:85:5 | LL | Foo {}, | ^^^ @@ -81,7 +117,7 @@ LL | Foo {}, = help: consider a manual implementation of `Default` error: default variant must be exhaustive - --> $DIR/macros-nonfatal-errors.rs:61:5 + --> $DIR/macros-nonfatal-errors.rs:93:5 | LL | #[non_exhaustive] | ----------------- declared `#[non_exhaustive]` here @@ -91,43 +127,43 @@ LL | Foo, = help: consider a manual implementation of `Default` error: asm template must be a string literal - --> $DIR/macros-nonfatal-errors.rs:66:10 + --> $DIR/macros-nonfatal-errors.rs:98:10 | LL | asm!(invalid); | ^^^^^^^ error: inline assembly must be a string literal - --> $DIR/macros-nonfatal-errors.rs:67:15 + --> $DIR/macros-nonfatal-errors.rs:99:15 | LL | llvm_asm!(invalid); | ^^^^^^^ error: concat_idents! requires ident args. - --> $DIR/macros-nonfatal-errors.rs:69:5 + --> $DIR/macros-nonfatal-errors.rs:101:5 | LL | concat_idents!("not", "idents"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:71:17 + --> $DIR/macros-nonfatal-errors.rs:103:17 | LL | option_env!(invalid); | ^^^^^^^ error: expected string literal - --> $DIR/macros-nonfatal-errors.rs:72:10 + --> $DIR/macros-nonfatal-errors.rs:104:10 | LL | env!(invalid); | ^^^^^^^ error: expected string literal - --> $DIR/macros-nonfatal-errors.rs:73:10 + --> $DIR/macros-nonfatal-errors.rs:105:10 | LL | env!(foo, abr, baz); | ^^^ error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined - --> $DIR/macros-nonfatal-errors.rs:74:5 + --> $DIR/macros-nonfatal-errors.rs:106:5 | LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -135,7 +171,7 @@ LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) error: format argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:76:13 + --> $DIR/macros-nonfatal-errors.rs:108:13 | LL | format!(invalid); | ^^^^^^^ @@ -146,19 +182,19 @@ LL | format!("{}", invalid); | ^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:78:14 + --> $DIR/macros-nonfatal-errors.rs:110:14 | LL | include!(invalid); | ^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:80:18 + --> $DIR/macros-nonfatal-errors.rs:112:18 | LL | include_str!(invalid); | ^^^^^^^ error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) - --> $DIR/macros-nonfatal-errors.rs:81:5 + --> $DIR/macros-nonfatal-errors.rs:113:5 | LL | include_str!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -166,13 +202,13 @@ LL | include_str!("i'd be quite surprised if a file with this name existed") = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:82:20 + --> $DIR/macros-nonfatal-errors.rs:114:20 | LL | include_bytes!(invalid); | ^^^^^^^ error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) - --> $DIR/macros-nonfatal-errors.rs:83:5 + --> $DIR/macros-nonfatal-errors.rs:115:5 | LL | include_bytes!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -180,10 +216,10 @@ LL | include_bytes!("i'd be quite surprised if a file with this name existed = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) error: trace_macros! accepts only `true` or `false` - --> $DIR/macros-nonfatal-errors.rs:85:5 + --> $DIR/macros-nonfatal-errors.rs:117:5 | LL | trace_macros!(invalid); | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 21 previous errors +error: aborting due to 27 previous errors