Skip to content

add macros for generating Default impls#5257

Open
telcharr wants to merge 6 commits into
rust-lang:mainfrom
telcharr:feature/default-macro
Open

add macros for generating Default impls#5257
telcharr wants to merge 6 commits into
rust-lang:mainfrom
telcharr:feature/default-macro

Conversation

@telcharr

@telcharr telcharr commented Jul 7, 2026

Copy link
Copy Markdown

Description

Adds impl_default!, s_with_default!, and s_no_extra_traits_with_default! as a start for #4975. Unions get no implicit Default so a union field would need to supply one via #[custom_default(unsafe { mem::zeroed::<U>() })]. As discussed, custom_default needs to be the first attribute on a field since the macro matches it literally.

Checklist

  • Relevant tests in libc-test/semver have been updated
  • No placeholder or unstable values like *LAST or *MAX are
    included (see #3131)
  • Tested locally (cd libc-test && cargo test --target mytarget);
    especially relevant for platforms that may not be checked in CI

@rustbot label +stable-nominated

@rustbot rustbot added S-waiting-on-review stable-nominated This PR should be considered for cherry-pick to libc's stable release branch labels Jul 7, 2026

@tgross35 tgross35 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for putting this together! It looks very workable. I have a handful of requests but all style/maintainability.

Would you be able to add a commit that makes use of this (replacing s!) in a few small places so we make sure it works in situ? Fine to do that in a separate PR, if you prefer, as long as it's coming soon.

View changes since this review

Comment thread src/macros.rs Outdated
Comment on lines +532 to +533
/// Like [`s`], but also generates a `Default` impl for every struct in the block.
macro_rules! s_with_default {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: move this and s_no_extra_traits_with_default to directly below s_no_extra_traits! to keep them together (this file kind of flows from most important to less important / helpers)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to order the macros:

  • s
  • s_paren
  • s_no_extra_traits
  • s_with_default
  • s_no_extra_traits_with_default
  • impl_default

So all the ss are together - currently impl_default is in the middle

Comment thread src/macros.rs Outdated
Comment thread src/macros.rs Outdated
Comment thread src/macros.rs Outdated
Comment thread src/macros.rs Outdated
s_with_default! {
pub struct S3 {
pub a: u32,
#[custom_default([0; 64])]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you make this something other than the default like [1; 64]? To make sure the field attribute is working rather than the derive.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

@tgross35 tgross35 Jul 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that there isn't currently a test for this, the change is kind of pointless without it 🙂 could you assert the field values in S3 and the other structs/unions in that area?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I guess S3's pattern pattern is already checked with CustomDefault

Comment thread src/macros.rs
Comment thread src/macros.rs Outdated
Comment thread src/macros.rs Outdated
@rustbot

rustbot commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@telcharr

Copy link
Copy Markdown
Author

Added a commit converting new/linux_uapi/linux/can.rs since it hits most cases. The only things it doesn't cover is #[cfg] and doc comments. If you'd like me to add a new commit implementing the macros that covers those cases let me know.

@rustbot ready

@tgross35 tgross35 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few small requests here and in the comments above, then I think this should be good to go. Could you squash please? (The change updating can.rs can stay a separate commit)

View changes since this review

Comment thread src/macros.rs
/// for `Default`. If it does not exist, `Default::default()` is used instead. In either case, the
/// field is added to `processed_fields` with `#[custom_default]` stripped if necessary, and
/// `impl_default` is invoked again with the remaining fields.
macro_rules! impl_default {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename this to struct_with_default or similar since it also emits the struct itself

Comment thread src/macros.rs Outdated
s_with_default! {
pub struct S3 {
pub a: u32,
#[custom_default([0; 64])]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I guess S3's pattern pattern is already checked with CustomDefault

Comment thread src/macros.rs
Comment on lines +346 to +353
impl ::core::default::Default for $name {
// Field doc comments get forwarded to the initializer alongside `#[cfg]`
// they're harmless there but the lint fires, so silence it.
#[allow(unused_doc_comments)]
fn default() -> Self {
Self { $($processed_field_defaults)* }
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm realizing that something like #[cfg(target_arch = "x86_64")] on the whole struct may not work correctly since impl Default won't get the same config. I think we might need to filter the struct attributes and pass any cfg(...) to Default.

That can be done in a followup though, this gets us most of the way.

(Debug for unions has the same issue, guess we just haven't hit it.)

Comment thread src/macros.rs
Comment on lines +795 to +802
s_with_default! {
struct FieldAttrs {
#[cfg(target_arch = "x86_64")]
a: u8,
#[cfg(not(target_arch = "x86_64"))]
a: u64,
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a #[cfg(target_arch = "x86_64")] field that doesn't have a cfg(not(...)) to go with it? Just thinking about how a: Default::default() technically works on all platforms here, but it might not always.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

O-linux S-waiting-on-author stable-nominated This PR should be considered for cherry-pick to libc's stable release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants