llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Mateusz Pusz (mpusz)
<details>
<summary>Changes</summary>
`APValue::printPretty` prints a class value as a braced list of its bases and
fields, recursively. So a value of an empty class printed one pair of braces
per level of empty bases. An empty class has only one value, so these braces
tell the reader nothing. This patch prints `{}` for a class for which
`CXXRecordDecl::isEmpty()` holds. A class that is not empty keeps its braces
because they show which subobject each value belongs to, which was the concern
raised in the issue.
```cpp
struct empty {};
struct metre : empty {};
struct second : empty {};
template<auto V> struct quantity {};
void take(quantity<second{}>);
void f() { take(quantity<metre{}>{}); }
```
Before: `no known conversion from 'quantity<metre{{}}>' to
'quantity<second{{}}>'`
After: `no known conversion from 'quantity<metre{}>' to
'quantity<second{}>'`
Outside diagnostics, this also changes the `-ast-print` output and the
`DW_AT_name` of such a specialization in DWARF, for example from
`quantity<ns::metre{{}}>` to `quantity<ns::metre{}>`. Both now
print the same braces as the diagnostics.
The existing test for #<!-- -->66744 pinned the old output and is updated. Two
cases are added, for a deeper empty hierarchy and for a non-empty class that
keeps its braces. `check-clang` passes.
This patch was developed with the help of an AI assistant (Claude). I have
reviewed and tested every change.
Fixes #<!-- -->88502
---
Full diff: https://github.com/llvm/llvm-project/pull/232949.diff
2 Files Affected:
- (modified) clang/lib/AST/APValue.cpp (+7-1)
- (modified) clang/test/AST/ast-nttp-template-tree-compares.cpp (+26-3)
``````````diff
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index 97023be49c715b..1e33ffd4da8b11 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -1026,9 +1026,15 @@ void APValue::printPretty(raw_ostream &Out, const
PrintingPolicy &Policy,
return;
}
case APValue::Struct: {
+ const auto *RD = Ty->castAsRecordDecl();
+ // Every value of an empty class is the same value, so the nested braces of
+ // its (empty) bases carry no information.
+ if (const auto *CD = dyn_cast<CXXRecordDecl>(RD); CD && CD->isEmpty()) {
+ Out << "{}";
+ return;
+ }
Out << '{';
llvm::ListSeparator Comma;
- const auto *RD = Ty->castAsRecordDecl();
if (unsigned N = getStructNumBases()) {
const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD);
CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin();
diff --git a/clang/test/AST/ast-nttp-template-tree-compares.cpp
b/clang/test/AST/ast-nttp-template-tree-compares.cpp
index a767e385b8f0ab..3cbb950344736f 100644
--- a/clang/test/AST/ast-nttp-template-tree-compares.cpp
+++ b/clang/test/AST/ast-nttp-template-tree-compares.cpp
@@ -9,8 +9,31 @@ template<auto> struct quantity { }; // #QUANT
void use() {
quantity<divided_units<metre{}, second{}>{}> q{};
quantity<metre{}> q2 = q;
- // expected-error@-1 {{no viable conversion from
'quantity<divided_units<metre{}, second{}>{{}}>' to 'quantity<metre{{}}>'}}
- // expected-note@#QUANT {{candidate constructor (the implicit copy
constructor) not viable: no known conversion from
'quantity<divided_units<metre{}, second{}>{}>' to 'const quantity<metre{{}}> &'
for 1st argument}}
- // expected-note@#QUANT {{candidate constructor (the implicit move
constructor) not viable: no known conversion from
'quantity<divided_units<metre{}, second{}>{}>' to 'quantity<metre{{}}> &&' for
1st argument}}
+ // expected-error@-1 {{no viable conversion from
'quantity<divided_units<metre{}, second{}>{}>' to 'quantity<metre{}>'}}
+ // expected-note@#QUANT {{candidate constructor (the implicit copy
constructor) not viable: no known conversion from
'quantity<divided_units<metre{}, second{}>{}>' to 'const quantity<metre{}> &'
for 1st argument}}
+ // expected-note@#QUANT {{candidate constructor (the implicit move
constructor) not viable: no known conversion from
'quantity<divided_units<metre{}, second{}>{}>' to 'quantity<metre{}> &&' for
1st argument}}
}
+
+// An empty class has a single value, so the braces of its empty bases are not
+// printed, however deep the hierarchy.
+struct kilometre : metre { };
+template<auto> struct quantity2 { }; // #QUANT2
+
+void use_deep() {
+ quantity2<kilometre{}> q{};
+ quantity2<second{}> q2 = q;
+ // expected-error@-1 {{no viable conversion from 'quantity2<kilometre{}>' to
'quantity2<second{}>'}}
+ // expected-note@#QUANT2 2{{candidate constructor}}
+}
+
+// A class with data members keeps the braces that position each subobject.
+struct tagged : empty { int v; };
+template<auto> struct quantity3 { }; // #QUANT3
+
+void use_non_empty() {
+ quantity3<tagged{{}, 1}> q{};
+ quantity3<tagged{{}, 2}> q2 = q;
+ // expected-error@-1 {{{no viable conversion from 'quantity3<tagged{{}, 1}>'
to 'quantity3<tagged{{}, 2}>'}}}
+ // expected-note@#QUANT3 2{{candidate constructor}}
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/232949
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits