Skip to content

normalize_doc_attributes + wrap_comments can leave trailing whitespace #7069

Open

Description

@ahl

Summary

I tried to format this code:

// rustfmt-normalize_doc_attributes: true
// rustfmt-wrap_comments: true

pub trait ClientSystemAlertsExt {
    #[doc = "If this is included, only alerts created at or after this time will be returned.\n```ignore\nx\n```"]
    fn alert_list(&self) -> builder::AlertList<'_>;
}

Expected behavior

No trailing whitespace in any line (and no changes after running rustfmt on the formatted code i.e. idempotency).

Actual behavior

Trailing whitespace after " returned."

Configuration

As noted above: normalize_doc_attributes + wrap_comments

Activity

  1. added
    C-bugCategory: this is a bug; use also I-* labels for specific bug kinds, e.g. I-non-idempotency or I-ICE
    on Aug 25, 2026
  2. added
    needs-triageThis issue or PR needs triaging to determine its status. Remove label once sufficiently triaged.
    on Aug 25, 2026
  3. ytmimi commented on Aug 25, 2026

    @ytmimi
    Contributor

    Seems related to #6695

  4. ytmimi commented on Aug 25, 2026

    @ytmimi
    Contributor

    Confirmed I can reproduce this with: rustfmt 1.10.0-nightly (138684c 2026-08-25)

    cargo run --bin rustfmt -- --config=normalize_doc_attributes=true,wrap_comments=true

    Input

    pub trait ClientSystemAlertsExt {
        #[doc = "If this is included, only alerts created at or after this time will be returned.\n```ignore\nx\n```"]
        fn alert_list(&self) -> builder::AlertList<'_>;
    }

    Output

    pub trait ClientSystemAlertsExt {
        ///If this is included, only alerts created at or after this time will be
        /// returned. 
        /// ```ignore
        /// x
        /// ```
        fn alert_list(&self) -> builder::AlertList<'_>;
    }
    error[internal]: left behind trailing whitespace
     --> <stdin>:6:6:18
      |
    6 |     /// returned. 
      |                  ^
      |
      = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals
    
    warning: rustfmt has failed to format. See previous 1 errors.
    
  5. added
    A-doc-commentsArea: doc comments `/** */`, `#[doc = "..."]`, `///` and `//!`.
    I-trailing-whitespaceIssue: internal error; left behind trailing whitespace
    and removed
    needs-triageThis issue or PR needs triaging to determine its status. Remove label once sufficiently triaged.
    on Aug 25, 2026
  6. ahl commented on Aug 25, 2026

    @ahl
    ContributorAuthor

    I have a fix that doesn't regress anything else in the test suite:

    --- a/src/comment.rs
    +++ b/src/comment.rs
    @@ -894,6 +894,11 @@ impl<'a> CommentRewrite<'a> {
                     self.result.pop();
                 }
                 if self.code_block_attr.is_some() && self.is_prev_line_multi_line {
    +                // The fence opens on its own line, so drop the space that was added to
    +                // continue the previous wrapped line.
    +                if self.result.ends_with(' ') {
    +                    self.result.pop();
    +                }
                     self.result.push_str(&self.comment_line_separator);
                 }
                 self.result.push_str(line);

    Happy to submit a PR if that would be useful.

  7. ytmimi commented on Aug 25, 2026

    @ytmimi
    Contributor

    @ahl instead of popping off a single whitespace character I think we should understand why it was incorrectly added in the first place. We should prevent that from happening instead.

  8. ahl commented on Aug 25, 2026

    @ahl
    ContributorAuthor

    I tried that first because it's a pattern I see quite a bit. How about this instead?

    --- a/src/comment.rs
    +++ b/src/comment.rs
    @@ -818,7 +818,10 @@ impl<'a> CommentRewrite<'a> {
                 if line.is_empty() {
                     return false;
                 }
    -        } else if self.is_prev_line_multi_line && !line.is_empty() {
    +        } else if self.is_prev_line_multi_line
    +            && !line.is_empty()
    +            && !self.code_block_attr.is_some()
    +        {
                 self.result.push(' ')
             } else if is_last && line.is_empty() {
                 // trailing blank lines are unwanted
    @@ -893,9 +896,6 @@ impl<'a> CommentRewrite<'a> {
                     // Remove space if this is an empty comment or a doc comment.
                     self.result.pop();
                 }
    -            if self.code_block_attr.is_some() && self.is_prev_line_multi_line {
    -                self.result.push_str(&self.comment_line_separator);
    -            }
                 self.result.push_str(line);
                 self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
                 self.is_prev_line_multi_line = false;

    I don't fully understand the rationale for the block of code I deleted, but it seems to only impact this one case now and deleting it is an improvement.

  9. ytmimi commented on Aug 25, 2026

    @ytmimi
    Contributor

    I don't fully understand the rationale for the block of code I deleted, but it seems to only impact this one case now and deleting it is an improvement.

    @ahl check the git history to figure out why that was added?

  10. ahl commented on Aug 25, 2026

    @ahl
    ContributorAuthor

    Looks liked a related case: #6417

  11. ahl commented on Sep 2, 2026

    @ahl
    ContributorAuthor

    @ytmimi please let me know if a PR along these lines would be reasonable.

  12. ytmimi commented on Sep 2, 2026

    @ytmimi
    Contributor

    Yeah sure, let's go for it. Let's include the current example as a test case, but let's also see if we need to add any others to catch edge cases based on these code changes.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-doc-commentsArea: doc comments `/** */`, `#[doc = "..."]`, `///` and `//!`.C-bugCategory: this is a bug; use also I-* labels for specific bug kinds, e.g. I-non-idempotency or I-ICEI-trailing-whitespaceIssue: internal error; left behind trailing whitespaceUO-normalize_doc_attributesUnstable option: normalize_doc_attributesUO-wrap_commentsUnstable option: wrap_comments

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions