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&lt;auto V&gt; struct quantity {};
void take(quantity&lt;second{}&gt;);
void f() { take(quantity&lt;metre{}&gt;{}); }
```

Before: `no known conversion from 'quantity&lt;metre{{}}&gt;' to 
'quantity&lt;second{{}}&gt;'`
After: `no known conversion from 'quantity&lt;metre{}&gt;' to 
'quantity&lt;second{}&gt;'`

Outside diagnostics, this also changes the `-ast-print` output and the 
`DW_AT_name` of such a specialization in DWARF, for example from 
`quantity&lt;ns::metre{{}}&gt;` to `quantity&lt;ns::metre{}&gt;`. 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

Reply via email to