[clang] [clang]: support std::meta::info for primitive types (PR #190356)

via cfe-commits cfe-commits at lists.llvm.org
Mon May 4 05:07:34 PDT 2026


================
@@ -494,6 +500,61 @@ static void profileIntValue(llvm::FoldingSetNodeID &ID, const llvm::APInt &V) {
     ID.AddInteger((uint32_t)V.extractBitsAsZExtValue(std::min(32u, N - I), I));
 }
 
+/// Unwrap reflected type for profiling
+static QualType unwrapReflectedTypeForProfile(QualType QT) {
+
+  // TODO(Reflection)
+
+  /// [expr.reflect] p5, if a reflect-expression R matches the form ^^reflection-name
+  /// it is interpreted as such; the identifier is looked up and the representation of R is determined as follows:
+  /// - if lookup fines a type alias A, R represents the type the underlying entity of A if A
+  ///   was introduced by the declaration of a template parameter; otherwise, R represents A.
+
+  /// [expr.reflect] p6, Given reflect-expression R of the form ^^type-id,
+  /// if type-id is neither a placeholder type nor in the form of nested-name-specifier_opt template_opt simple-template-id
+  /// then R represents the type denoted by the type-id
+
+  bool IsConst = QT.isConstQualified();
+  bool IsVolatile = QT.isVolatileQualified();
+  bool UnwrapAliases = (IsConst || IsVolatile);
+
+  void *AsPtr;
+  do {
+    AsPtr = QT.getAsOpaquePtr();
+    if (const auto *DTT = dyn_cast<DecltypeType>(QT)) {
+      QT = DTT->desugar();
+      UnwrapAliases = true;
+    }
+    if (const auto *UT = dyn_cast<UsingType>(QT); UT && UnwrapAliases)
+      QT = UT->desugar();
+    if (const auto *TDT = dyn_cast<TypedefType>(QT); TDT && UnwrapAliases)
+      QT = TDT->desugar();
+  } while (QT.getAsOpaquePtr() != AsPtr);
+
+  if (IsConst)
+    QT = QT.withConst();
+  if (IsVolatile)
+    QT = QT.withVolatile();
+
+  return QT;
+}
+
----------------
manuel5975p wrote:

Is the `UnwrapAliases = (IsConst || IsVolatile)` rule actually what we want here? The cv qualifiers should not be what decides whether two reflections compare equal. concretely `^^int32_t` should differ from `^^int` even with neithr qualifier, and `^^decltype(x)` should equal `^^int` even when both are const. The current code gets both of those worng.

Could the profile be defined directly on the canonical unqualified type plus a typedef discriminator, with cv qualifiers profiled separately? Something like:

```suggestion
static void profileReflectedType(llvm::FoldingSetNodeID &ID, QualType QT) {
  QT.getQualifiers().Profile(ID);
  if (const auto *TDT = QT->getAs<TypedefType>()) {
    ID.AddBoolean(true);
    ID.AddPointer(TDT->getDecl()->getCanonicalDecl());
    return;
  }
  ID.AddBoolean(false);
  QT.getCanonicalType().getUnqualifiedType().Profile(ID);
}
```

That gives `^^int32_t != ^^int`, `^^int == ^^decltype(a)`, `^^struct Foo == ^^class Foo`, `^^const int == ^^const int` without a fixpoint loop. The Bloomberg fork uses this shape in [`clang/lib/AST/APValue.cpp` L513-L540](https://github.com/bloomberg/clang-p2996/blob/9ffb96e3ce362289008e14ad2a79a249f58aa90a/clang/lib/AST/APValue.cpp#L513-L540). sugars like `AttributedType` or template specialization sugar can be added later when Sema admits them as distinct reflections. Worth adding tests for those four cases in this PR?

https://github.com/llvm/llvm-project/pull/190356


More information about the cfe-commits mailing list