Skip to content

Conversation

l0rinc
Copy link
Contributor

@l0rinc l0rinc commented Jun 25, 2025

Updates .clang-format file to reflect latest supported Clang-Format standards while preserving most of the existing formatting behavior, except for the very last commit which aligns AfterStruct brace placement with AfterClass for code formatting.

The first commit reformats a file containing a C++ struct, the second one modifies the formatting and reformats the same file to show the difference. See #32813 (comment) for motivation for the change to unify struct formatting behavior across versions.

@DrahtBot
Copy link
Contributor

DrahtBot commented Jun 25, 2025

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/32813.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK maflcko
Stale ACK hodlinator

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

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

last commit seems fine, but the others i am not sure. at a minimum you'll have to drop the scripted diffs from executing, because they can't be reproduced anyway with different clang-format versions

@DrahtBot
Copy link
Contributor

🚧 At least one of the CI tasks failed.
Task lint: https://github.com/bitcoin/bitcoin/runs/44780552247
LLM reason (✨ experimental): The CI failure is caused by errors in the lint check, related to code style or formatting issues.

Hints

Try to run the tests locally, according to the documentation. However, a CI failure may still
happen due to a number of reasons, for example:

  • Possibly due to a silent merge conflict (the changes in this pull request being
    incompatible with the current code in the target branch). If so, make sure to rebase on the latest
    commit of the target branch.

  • A sanitizer issue, which can only be found by compiling with the sanitizer and running the
    affected test.

  • An intermittent issue.

Leave a comment here, if you need help tracking down a confusing failure.

@l0rinc l0rinc force-pushed the l0rinc/clang-format branch 2 times, most recently from c3ef744 to 5a48369 Compare June 25, 2025 22:03
l0rinc and others added 2 commits June 27, 2025 11:31
Regenerated `.clang-format` from current configs to replace deprecated keys with up-to-date equivalents.
Also added all current formatter default values to guard against version differences.

The configs were updated with the following command (using v16 for maximal compatibility):
   $(brew --prefix llvm@16)/bin/clang-format -dump-config -style=file:src/.clang-format

The new config was tested with:
   $(brew --prefix llvm@16)/bin/clang-format -i src/deploymentinfo.h

Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
The new config was tested with the same file as the previous commit to showcase the changes:
  $(brew --prefix llvm@16)/bin/clang-format -i src/deploymentinfo.h
@l0rinc l0rinc force-pushed the l0rinc/clang-format branch from 5a48369 to 94364a7 Compare June 27, 2025 09:33
@l0rinc l0rinc marked this pull request as ready for review June 29, 2025 08:11
@l0rinc l0rinc changed the title clang-format: modernize and realign clang-format configuration clang-format: align brace-after-struct and *-class formatting Jun 29, 2025
Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

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

I haven't checked if this fixes the issues with your IDE, but I guess it makes sense either way to get the clang-format config up to date. clang-16 is the minimum required for about a year now, so every developer should have access to clang-format-16 in some way or another.

I've recreated the commits on Ubuntu and reviewed the diff:

review ACK 94364a7 🥙

Show signature

Signature:

untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
trusted comment: review ACK 94364a7d5403d9d480ebc065f8709c6dd21e543f 🥙
xsnBRKa1+85+2JOjTRQ1kZgSlBHhVZxj7LlQpMQNkd5vPsoJ/6a84fiaWp9pAnna9VGz0/DA4J3jNoByA1TuCg==

l0rinc added a commit to l0rinc/bitcoin that referenced this pull request Jul 10, 2025
Feeds the file name string directly into the hasher instead of pre-hashing it first. The resuoting hash changes of course, but that doesn't affect us since it's only stored in-memory.

Fixes: bitcoin#32604 (comment)

A few other related nits were also addressed here:
* Comment was redundant, `CSipHasher` is used in other hashers all over the codebase
* `static_cast<size_t>` skewed the whole line, changed to shorter functional-style cast
* struct formatting is aligned with class formatting - see bitcoin#32813
l0rinc added a commit to l0rinc/bitcoin that referenced this pull request Jul 10, 2025
Feeds the file name string directly into the hasher instead of pre-hashing it first. The resulting hash changes of course, but that doesn't affect us since it's only stored in-memory.

Fixes: bitcoin#32604 (comment)

A few other related nits were also addressed here:
* Comment was redundant, `CSipHasher` is used in other hashers all over the codebase
* `static_cast<size_t>` skewed the whole line, changed to shorter functional-style cast
* struct formatting is aligned with class formatting - see bitcoin#32813
l0rinc added a commit to l0rinc/bitcoin that referenced this pull request Jul 10, 2025
Feeds the file name string directly into the hasher instead of pre-hashing it first. The resulting hash changes of course, but that doesn't affect us since it's only stored in-memory.

Fixes: bitcoin#32604 (comment)

A few other related nits were also addressed here:
* Comment was redundant, `CSipHasher` is used in other hashers all over the codebase
* `static_cast<size_t>` skewed the whole method, changed to shorter functional-style cast
* struct formatting is aligned with class formatting - see bitcoin#32813
@maflcko maflcko requested a review from hebasto July 11, 2025 09:12
Comment on lines +100 to +115
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
Copy link
Member

Choose a reason for hiding this comment

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

unrelated note: I understand the setting IncludeBlocks is set to Preserve (and it should probably stay this way by default, but it would be nice to update the other Include* settings (in another pull request) to properly sort the includes: (1) the main include, (2) everything else (Bitcoin Core includes) (3) third-party library includes (boost, Qt), (4) stdlib includes (those that do not end in .h). This way, one could toggle the IncludeBlocks to get the desired behavior.

@@ -67,7 +67,7 @@ Coding Style (C++)
[src/.clang-format](/src/.clang-format). You can use the provided
[clang-format-diff script](/contrib/devtools/README.md#clang-format-diffpy)
tool to clean up patches automatically before submission.
- Braces on new lines for classes, functions, methods.
- Braces on new lines for classes, structs, functions, methods.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why change the C++ Coding Style? I got used to the current one, which encourages structs for POD as a separate thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can define it that way as well (though I don't agree with the distinction vs classes), but not specifying it directly results in different versions formatting structs differently, so we should define it explicitly

Copy link
Contributor

Choose a reason for hiding this comment

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

Ran clang-format -i -- **.cpp **.h **.hpp in src/ for both AfterStruct true & false, and compared diffs. Man was it close.

true (94364a7) false
struct\n{ struct {
85'849 lines 85'659 lines

Even though struct & class can be used interchangeably in C++, only with different defaults for public/private, I think we might as well benefit from the fact that we have 2 concepts and use them to communicate which types are POD (more C-like) or not. (C# includes both too but places limits on struct such as disabling support for inheritance and treating them as value types by default).

I took for granted that the omission of struct on this line in developer-notes.md was intentional. Comes from #4498, but conversation unfortunately doesn't touch on struct. Author of that PR copyrighted a C-only library one year earlier (https://github.com/bitcoin-core/secp256k1/blob/master/COPYING#L1). It also has opening curlies on same line as struct.

Happy to have explicitly defined, but my vote is for false and not changing developer-notes.md. - Dropping the second commit.

Copy link
Contributor Author

@l0rinc l0rinc Aug 27, 2025

Choose a reason for hiding this comment

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

I would be fine with both as long as it's explicit. I still find the rationale that struct and class should be formatted similarly, it's harder for me to explain why struct is more like a for loop than a class...

85'849 lines

I have no idea what these numbers mean, I checked same-line opening braces with

% grep -E '^\s*\bstruct\b\s+[^;{]*\{' --include="*.h" --include="*.cpp" -r src/ | wc -l
     393

and quickly vibe coded a script that does newlines:

vibe-Details
#!/bin/bash

echo "Analyzing struct brace placement in Bitcoin Core..."

# Count same-line braces
same_line=$(grep -E '^\s*struct\s+[^;{]*\{' --include="*.h" --include="*.cpp" -r src/ | wc -l)

# Count next-line braces using awk
next_line=$(find src/ \( -name "*.cpp" -o -name "*.h" \) -exec awk '
/^[[:space:]]*struct[[:space:]]+[^;{]*$/ {
    struct_line = NR
    getline
    if (/^[[:space:]]*\{/) {
        count++
    }
}
END { print count+0 }
' {} \; | awk '{sum+=$1} END {print sum}')

echo "Structs with same-line brace: $same_line"
echo "Structs with next-line brace: $next_line"
echo "Total: $((same_line + next_line))"

which vibe-revealed:

Analyzing struct brace placement in Bitcoin Core...
Structs with same-line brace:      393
Structs with next-line brace: 223
Total: 616

So the counts don't really matter in my opinion, we have a few hundred of each, there's no clear winner based on usage, let's come up with better arguments for either.

Copy link
Contributor

@hodlinator hodlinator Aug 29, 2025

Choose a reason for hiding this comment

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

The line-counts where from the resulting git diffs. Admittedly they are imprecise due to surrounding context and other clang-format changes, but they give a rough relative estimate.

Thanks for vibing, almost double on same line. I'd say that does matter.

Edit:

it's harder for me to explain why struct is more like a for loop than a class...

Maybe seeing struct as a small/passive/record thing and seeing class as more of an alive/process thing with multiple methods and internal logic makes it closer to a function? Main thing for me is to keep to what a majority of the current code and coding style says, otherwise this change should probably be discussed more broadly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Admittedly they are imprecise

I'd say ~85000 vs ~400 is a bit more than imprecise :)

almost double on same line

That's not how we usually decide outcomes, rather by better explanations - especially since many of those aren't counting declarations, e.g

I'm fine with both, but have better explanations for the one I'm proposing. Ultimately I don't think it matters much, as long as it's explicit since current behavior results in inconsistencies.

Maybe seeing struct as a small/passive/record thing and seeing class as more of an alive/process

That sounds more philosophical to me, I don't think that's how we're using them (or how formatting is usually decided)? Most definitions I see state: it's just a class with public members, e.g. https://en.wikipedia.org/wiki/Struct_(C_programming_language)#C++

a class is the same as a struct but with different default visibility

Not sure why the formatting should be closer to an if or a switch or a loop, I don't see how it's closer to those that to a class.

Clang-format itself usually bundles the class and struct formatting together:

Copy link
Contributor

@hodlinator hodlinator left a comment

Choose a reason for hiding this comment

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

ACK 7c9b3e1 (first commit)

Ran clang-format -dump-config -style=file:src/.clang-format > foo on that commit and diffed foo against src/.clang-format. Only differences where added/elaborated settings from me running Clang-format 19. Makes sense to keep the format at the minimum version we support.

@@ -67,7 +67,7 @@ Coding Style (C++)
[src/.clang-format](/src/.clang-format). You can use the provided
[clang-format-diff script](/contrib/devtools/README.md#clang-format-diffpy)
tool to clean up patches automatically before submission.
- Braces on new lines for classes, functions, methods.
- Braces on new lines for classes, structs, functions, methods.
Copy link
Contributor

Choose a reason for hiding this comment

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

Ran clang-format -i -- **.cpp **.h **.hpp in src/ for both AfterStruct true & false, and compared diffs. Man was it close.

true (94364a7) false
struct\n{ struct {
85'849 lines 85'659 lines

Even though struct & class can be used interchangeably in C++, only with different defaults for public/private, I think we might as well benefit from the fact that we have 2 concepts and use them to communicate which types are POD (more C-like) or not. (C# includes both too but places limits on struct such as disabling support for inheritance and treating them as value types by default).

I took for granted that the omission of struct on this line in developer-notes.md was intentional. Comes from #4498, but conversation unfortunately doesn't touch on struct. Author of that PR copyrighted a C-only library one year earlier (https://github.com/bitcoin-core/secp256k1/blob/master/COPYING#L1). It also has opening curlies on same line as struct.

Happy to have explicitly defined, but my vote is for false and not changing developer-notes.md. - Dropping the second commit.

@DrahtBot DrahtBot requested a review from hodlinator August 27, 2025 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants