Skip to content

Commit b8232b1

Browse files
authored
Rollup merge of rust-lang#101040 - danielhenrymantilla:no-bounds-for-default-annotated-derive, r=joshtriplett
Fix `#[derive(Default)]` on a generic `#[default]` enum adding unnecessary `Default` bounds That is, given something like: ```rs // #[default] on a generic enum does not add `Default` bounds to the type params. #[derive(Default)] enum MyOption<T> { #[default] None, Some(T), } ``` then `MyOption<T> : Default`_as currently implemented_ only holds when `T : Default`, as reported by ``@5225225`` [over Zulip](https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/.23.5Bderive.28Default.29.5D.20for.20enums.20with.20fields). This is contrary to [what the accepted RFC proposes](https://rust-lang.github.io/rfcs/3107-derive-default-enum.html#generated-bounds) (_i.e._, that `T` be allowed not to be itself `Default`), and indeed seems to be a rather unnecessary limitation.
2 parents 34a0e3f + 3d4980b commit b8232b1

15 files changed

+77
-2
lines changed

compiler/rustc_builtin_macros/src/deriving/bounds.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn expand_deriving_copy(
1616
let trait_def = TraitDef {
1717
span,
1818
path: path_std!(marker::Copy),
19+
skip_path_as_bound: false,
1920
additional_bounds: Vec::new(),
2021
generics: Bounds::empty(),
2122
supports_unions: true,

compiler/rustc_builtin_macros/src/deriving/clone.rs

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub fn expand_deriving_clone(
7272
let trait_def = TraitDef {
7373
span,
7474
path: path_std!(clone::Clone),
75+
skip_path_as_bound: false,
7576
additional_bounds: bounds,
7677
generics: Bounds::empty(),
7778
supports_unions: true,

compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub fn expand_deriving_eq(
2525
let trait_def = TraitDef {
2626
span,
2727
path: path_std!(cmp::Eq),
28+
skip_path_as_bound: false,
2829
additional_bounds: Vec::new(),
2930
generics: Bounds::empty(),
3031
supports_unions: true,

compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub fn expand_deriving_ord(
1919
let trait_def = TraitDef {
2020
span,
2121
path: path_std!(cmp::Ord),
22+
skip_path_as_bound: false,
2223
additional_bounds: Vec::new(),
2324
generics: Bounds::empty(),
2425
supports_unions: false,

compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pub fn expand_deriving_partial_eq(
8383
let trait_def = TraitDef {
8484
span,
8585
path: path_std!(cmp::PartialEq),
86+
skip_path_as_bound: false,
8687
additional_bounds: Vec::new(),
8788
generics: Bounds::empty(),
8889
supports_unions: false,

compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub fn expand_deriving_partial_ord(
3737
let trait_def = TraitDef {
3838
span,
3939
path: path_std!(cmp::PartialOrd),
40+
skip_path_as_bound: false,
4041
additional_bounds: vec![],
4142
generics: Bounds::empty(),
4243
supports_unions: false,

compiler/rustc_builtin_macros/src/deriving/debug.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub fn expand_deriving_debug(
2020
let trait_def = TraitDef {
2121
span,
2222
path: path_std!(fmt::Debug),
23+
skip_path_as_bound: false,
2324
additional_bounds: Vec::new(),
2425
generics: Bounds::empty(),
2526
supports_unions: false,

compiler/rustc_builtin_macros/src/deriving/decodable.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub fn expand_deriving_rustc_decodable(
2323
let trait_def = TraitDef {
2424
span,
2525
path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
26+
skip_path_as_bound: false,
2627
additional_bounds: Vec::new(),
2728
generics: Bounds::empty(),
2829
supports_unions: false,

compiler/rustc_builtin_macros/src/deriving/default.rs

+20
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub fn expand_deriving_default(
2424
let trait_def = TraitDef {
2525
span,
2626
path: Path::new(vec![kw::Default, sym::Default]),
27+
skip_path_as_bound: has_a_default_variant(item),
2728
additional_bounds: Vec::new(),
2829
generics: Bounds::empty(),
2930
supports_unions: false,
@@ -262,3 +263,22 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
262263
}
263264
}
264265
}
266+
267+
fn has_a_default_variant(item: &Annotatable) -> bool {
268+
struct HasDefaultAttrOnVariant {
269+
found: bool,
270+
}
271+
272+
impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant {
273+
fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) {
274+
if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
275+
self.found = true;
276+
}
277+
// no need to subrecurse.
278+
}
279+
}
280+
281+
let mut visitor = HasDefaultAttrOnVariant { found: false };
282+
item.visit_with(&mut visitor);
283+
visitor.found
284+
}

compiler/rustc_builtin_macros/src/deriving/encodable.rs

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ pub fn expand_deriving_rustc_encodable(
107107
let trait_def = TraitDef {
108108
span,
109109
path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
110+
skip_path_as_bound: false,
110111
additional_bounds: Vec::new(),
111112
generics: Bounds::empty(),
112113
supports_unions: false,

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
174174
use rustc_span::Span;
175175
use std::cell::RefCell;
176176
use std::iter;
177+
use std::ops::Not;
177178
use std::vec;
178179
use thin_vec::thin_vec;
179180
use ty::{Bounds, Path, Ref, Self_, Ty};
@@ -187,6 +188,9 @@ pub struct TraitDef<'a> {
187188
/// Path of the trait, including any type parameters
188189
pub path: Path,
189190

191+
/// Whether to skip adding the current trait as a bound to the type parameters of the type.
192+
pub skip_path_as_bound: bool,
193+
190194
/// Additional bounds required of any type parameters of the type,
191195
/// other than the current trait
192196
pub additional_bounds: Vec<Ty>,
@@ -596,7 +600,7 @@ impl<'a> TraitDef<'a> {
596600
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
597601
}).chain(
598602
// require the current trait
599-
iter::once(cx.trait_bound(trait_path.clone()))
603+
self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone()))
600604
).chain(
601605
// also add in any bounds from the declaration
602606
param.bounds.iter().cloned()

compiler/rustc_builtin_macros/src/deriving/hash.rs

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub fn expand_deriving_hash(
2222
let hash_trait_def = TraitDef {
2323
span,
2424
path,
25+
skip_path_as_bound: false,
2526
additional_bounds: Vec::new(),
2627
generics: Bounds::empty(),
2728
supports_unions: false,

src/test/ui/deriving/deriving-default-enum.rs

+10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ enum Foo {
1212
Beta(NotDefault),
1313
}
1414

15+
// #[default] on a generic enum does not add `Default` bounds to the type params.
16+
#[derive(Default)]
17+
enum MyOption<T> {
18+
#[default]
19+
None,
20+
#[allow(dead_code)]
21+
Some(T),
22+
}
23+
1524
fn main() {
1625
assert_eq!(Foo::default(), Foo::Alpha);
26+
assert!(matches!(MyOption::<NotDefault>::default(), MyOption::None));
1727
}

src/test/ui/macros/macros-nonfatal-errors.rs

+21
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,24 @@ fn main() {
116116

117117
trace_macros!(invalid); //~ ERROR
118118
}
119+
120+
/// Check that `#[derive(Default)]` does use a `T : Default` bound when the
121+
/// `#[default]` variant is `#[non_exhaustive]` (should this end up allowed).
122+
const _: () = {
123+
#[derive(Default)]
124+
enum NonExhaustiveDefaultGeneric<T> {
125+
#[default]
126+
#[non_exhaustive]
127+
Foo, //~ ERROR default variant must be exhaustive
128+
Bar(T),
129+
}
130+
131+
fn assert_impls_default<T: Default>() {}
132+
133+
enum NotDefault {}
134+
135+
// Note: the `derive(Default)` currently bails early enough for trait-checking
136+
// not to happen. Should it bail late enough, or even pass, make sure to
137+
// assert that the following line fails.
138+
let _ = assert_impls_default::<NonExhaustiveDefaultGeneric<NotDefault>>;
139+
};

src/test/ui/macros/macros-nonfatal-errors.stderr

+11-1
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,21 @@ error: trace_macros! accepts only `true` or `false`
215215
LL | trace_macros!(invalid);
216216
| ^^^^^^^^^^^^^^^^^^^^^^
217217

218+
error: default variant must be exhaustive
219+
--> $DIR/macros-nonfatal-errors.rs:127:9
220+
|
221+
LL | #[non_exhaustive]
222+
| ----------------- declared `#[non_exhaustive]` here
223+
LL | Foo,
224+
| ^^^
225+
|
226+
= help: consider a manual implementation of `Default`
227+
218228
error: cannot find macro `llvm_asm` in this scope
219229
--> $DIR/macros-nonfatal-errors.rs:99:5
220230
|
221231
LL | llvm_asm!(invalid);
222232
| ^^^^^^^^
223233

224-
error: aborting due to 27 previous errors
234+
error: aborting due to 28 previous errors
225235

0 commit comments

Comments
 (0)