Issue 144328
Summary Bug Report: clang-format incorrectly reorders const and static for std::size_t
Labels clang-format
Assignees
Reporter AnonimiAngels
    ### Bug Report: clang-format incorrectly reorders `const` and `static` for `std::size_t` in C++11

**Description**
When using `clang-format` (version 19.1.7) with a C++11 style, qualifiers like `const` and `static` are incorrectly reordered when they appear after a namespaced type (e.g., `std::size_t const`). Specifically, `std::size_t const` is transformed into `std::const size_t`, and `std::size_t static` is transformed into `std::static size_t`. This reordering results in a compilation error, as `std::const` and `std::static` are not valid types or constructs within the `std` namespace. This issue occurs when the qualifier immediately follows the namespaced type.

---

**clang-format Version**
Debian clang-format version 19.1.7 (3)

---

**.clang-format Configuration**

```yaml
Language: Cpp
BasedOnStyle: LLVM
Standard: c++11

# Indentation
UseTab: Always
TabWidth: 4
IndentWidth: 4
ContinuationIndentWidth: 4
ConstructorInitializerIndentWidth: 4

# Braces
BreakBeforeBraces: Allman
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false

# Spacing
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesInParentheses: false
SpacesInAngles: false
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeRangeBasedForLoopColon: true
BitFieldColonSpacing: After

# Line breaks
ColumnLimit: 190
MaxEmptyLinesToKeep: 1
SpacesBeforeTrailingComments: 4
KeepEmptyLinesAtTheStartOfBlocks: true

# Alignment
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveBitFields: Consecutive
AlignConsecutiveDeclarations: None
AlignOperands: Align
AlignTrailingComments: true

# Pointers and references
PointerAlignment: Right
ReferenceAlignment: Right

# Qualifiers
QualifierAlignment: Custom
QualifierOrder: ['inline', 'static', 'friend', 'constexpr', 'const', 'volatile', 'restrict', 'type']

# Include sorting
SortIncludes: true
IncludeBlocks: Regroup
IncludeCategories:
  - Regex: '^<.*\\.h>'
    Priority: 1
  - Regex: '^<.*>'
    Priority: 2
 - Regex: '.*'
    Priority: 3

# Function formatting
AlwaysBreakAfterReturnType: None
AllowAllParametersOfDeclarationOnNextLine: true
BinPackParameters: false
BinPackArguments: false

# Misc
FixNamespaceComments: true
CompactNamespaces: false
NamespaceIndentation: All

# C++11 specific
Cpp11BracedListStyle: true

# Access modifiers
AccessModifierOffset: -4

# Case labels
IndentCaseLabels: false

# Comments
ReflowComments: true

# Penalty settings for better formatting
PenaltyBreakBeforeFirstCallParameter: 100
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60

# Break before operators
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeTernaryOperators: true

# Constructor initializers
BreakConstructorInitializers: BeforeColon
ConstructorInitializerAllOnOneLineOrOnePerLine: true

# Disable some auto-formatting that might conflict with style
DerivePointerAlignment: true
DisableFormat: false

# Empty line handling
SeparateDefinitionBlocks: Always
```

---

**Reproduction Steps**

1. Create a file (`test.cpp`) with the following code:

```cpp
template <typename T> auto replace_next(const T& p_value) -> void
{
    std::size_t const placeholder_pos = m_format_string.find("{}", m_current_pos); // Issue with 'const'
    // std::size_t static placeholder_pos; // This would also exhibit the error

    if (placeholder_pos != std::string::npos)
    {
        std::string const replacement = type_converter<T>::to_string(p_value);
 m_format_string.replace(placeholder_pos, 2, replacement);
 m_current_pos = placeholder_pos + replacement.length();
    }
}
```

2. Save the `.clang-format` configuration (shown above) in the same directory.
3. Run `clang-format -i test.cpp`

---

**Expected Behavior**
The `std::size_t const` (or `std::size_t static`) declaration should remain unchanged, or at most, be formatted to `const std::size_t` (or `static std::size_t`). The `QualifierOrder` specifies these qualifiers before 'type', so placing them before `std::size_t` is acceptable.

---

**Actual Behavior**
After formatting, `std::size_t const` becomes `std::const size_t`, and `std::size_t static` becomes `std::static size_t`. Both are syntactically incorrect in C++ and result in compilation errors.

---

**After-format Code (for `const` issue)**

```cpp
template <typename T> auto replace_next(const T& p_value) -> void
{
    std::const size_t placeholder_pos = m_format_string.find("{}", m_current_pos);
    if (placeholder_pos != std::string::npos)
    {
        const std::string replacement = type_converter<T>::to_string(p_value);
 m_format_string.replace(placeholder_pos, 2, replacement);
 m_current_pos = placeholder_pos + replacement.length();
 }
}
```

---

**Notes**
This appears to be a bug in qualifier reordering logic when applied to namespaced types. The formatter should detect namespace-prefixed types and avoid injecting qualifiers inside the namespace scope.

_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to