[clang] [libcxx] [lldb] [clang]: implement std::meta::is_type (PR #211653)
Nhat Nguyen via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 23 12:53:00 PDT 2026
https://github.com/changkhothuychung created https://github.com/llvm/llvm-project/pull/211653
This PR implements `std::meta::is_type(info)` by introducing a builtin `__builtin_meta_is_type`. It also includes two feature-test macros `__cpp_impl_reflection` and `__cpp_lib_reflection` introduced in [P2996 ](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2996r13.html). `__cpp_impl_reflection` is only enabled when `-freflection` is on, and `__cpp_lib_reflection` depends on `__cpp_impl_reflection`.
Header `<meta>` is created in libc++.
>From d31d40d2839e716fa95d3f624ef04dc329968d49 Mon Sep 17 00:00:00 2001
From: changkhothuychung <nhat7203 at gmail.com>
Date: Thu, 23 Jul 2026 14:59:10 -0400
Subject: [PATCH 1/2] support std::meta::info for primitive types
---
clang/include/clang/AST/APValue.h | 43 +++++++++-
clang/include/clang/AST/ASTContext.h | 1 +
clang/include/clang/AST/BuiltinTypes.def | 3 +
clang/include/clang/AST/ExprCXX.h | 21 +++--
clang/include/clang/AST/PropertiesBase.td | 25 ++++++
clang/include/clang/AST/Reflection.h | 39 +++++++++
clang/include/clang/AST/TypeBase.h | 5 ++
clang/include/clang/Basic/TargetInfo.h | 6 ++
.../include/clang/Serialization/ASTBitCodes.h | 5 +-
clang/lib/AST/APValue.cpp | 79 +++++++++++++++++++
clang/lib/AST/ASTContext.cpp | 9 +++
clang/lib/AST/ASTImporter.cpp | 34 +++++++-
clang/lib/AST/ByteCode/Compiler.cpp | 20 +++++
clang/lib/AST/ByteCode/Compiler.h | 1 +
clang/lib/AST/ByteCode/Context.cpp | 3 +
clang/lib/AST/ByteCode/Descriptor.cpp | 1 +
clang/lib/AST/ByteCode/Disasm.cpp | 2 +
clang/lib/AST/ByteCode/Interp.cpp | 2 +-
clang/lib/AST/ByteCode/Interp.h | 7 ++
.../lib/AST/ByteCode/InterpBuiltinBitCast.cpp | 2 +-
clang/lib/AST/ByteCode/InterpStack.h | 3 +
clang/lib/AST/ByteCode/InterpState.cpp | 1 +
clang/lib/AST/ByteCode/Opcodes.td | 9 ++-
clang/lib/AST/ByteCode/PrimType.cpp | 1 +
clang/lib/AST/ByteCode/PrimType.h | 6 ++
clang/lib/AST/ByteCode/Program.cpp | 1 +
clang/lib/AST/ByteCode/Program.h | 1 +
clang/lib/AST/ByteCode/Reflect.h | 60 ++++++++++++++
clang/lib/AST/ExprCXX.cpp | 11 +--
clang/lib/AST/ExprConstant.cpp | 77 +++++++++++++++++-
clang/lib/AST/ItaniumMangle.cpp | 73 ++++++++++++++++-
clang/lib/AST/MicrosoftMangle.cpp | 5 ++
clang/lib/AST/NSAPI.cpp | 1 +
clang/lib/AST/StmtPrinter.cpp | 11 ++-
clang/lib/AST/TextNodeDumper.cpp | 16 ++++
clang/lib/AST/Type.cpp | 10 +++
clang/lib/AST/TypeLoc.cpp | 1 +
clang/lib/Basic/TargetInfo.cpp | 2 +
clang/lib/CodeGen/CGDebugInfo.cpp | 2 +
clang/lib/CodeGen/CGExprConstant.cpp | 2 +
clang/lib/CodeGen/CodeGenModule.cpp | 2 +
clang/lib/CodeGen/CodeGenTypes.cpp | 7 ++
clang/lib/CodeGen/ItaniumCXXABI.cpp | 1 +
clang/lib/CodeGen/QualTypeMapper.cpp | 3 +
clang/lib/Sema/SemaExpr.cpp | 13 ++-
clang/lib/Sema/SemaOverload.cpp | 23 ++++--
clang/lib/Sema/SemaTemplate.cpp | 17 +++-
clang/lib/Sema/TreeTransform.h | 14 +++-
clang/lib/Serialization/ASTCommon.cpp | 3 +
clang/lib/Serialization/ASTReader.cpp | 3 +
clang/lib/Serialization/ASTReaderStmt.cpp | 15 +++-
clang/lib/Serialization/ASTWriterStmt.cpp | 15 +++-
.../UnifiedSymbolResolution/USRGeneration.cpp | 3 +
.../test/AST/ast-dump-APValue-reflection.cpp | 14 ++++
.../reflection-emit-meta-info-itanium.cpp | 7 ++
...s.cpp => reflection-emit-meta-info-ms.cpp} | 0
.../CodeGenCXX/reflection-mangle-itanium.cpp | 42 +++++++++-
clang/test/PCH/reflection.cpp | 14 ++++
clang/test/PCH/reflection_include.h | 1 +
clang/test/Sema/reflection-meta-info.fail.cpp | 56 +++++++++++++
clang/test/Sema/reflection-meta-info.pass.cpp | 77 ++++++++++++++++++
clang/tools/libclang/CIndex.cpp | 1 +
clang/unittests/AST/ASTImporterTest.cpp | 29 +++++++
.../TypeSystem/Clang/TypeSystemClang.cpp | 3 +
64 files changed, 925 insertions(+), 39 deletions(-)
create mode 100644 clang/include/clang/AST/Reflection.h
create mode 100644 clang/lib/AST/ByteCode/Reflect.h
create mode 100644 clang/test/AST/ast-dump-APValue-reflection.cpp
create mode 100644 clang/test/CodeGenCXX/reflection-emit-meta-info-itanium.cpp
rename clang/test/CodeGenCXX/{reflection-mangle-ms.cpp => reflection-emit-meta-info-ms.cpp} (100%)
create mode 100644 clang/test/PCH/reflection.cpp
create mode 100644 clang/test/PCH/reflection_include.h
create mode 100644 clang/test/Sema/reflection-meta-info.fail.cpp
create mode 100644 clang/test/Sema/reflection-meta-info.pass.cpp
diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h
index 9293266a41256..2f6efc670b6e8 100644
--- a/clang/include/clang/AST/APValue.h
+++ b/clang/include/clang/AST/APValue.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_AST_APVALUE_H
#define LLVM_CLANG_AST_APVALUE_H
+#include "clang/AST/Reflection.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/APFixedPoint.h"
#include "llvm/ADT/APFloat.h"
@@ -141,7 +142,8 @@ class APValue {
Struct,
Union,
MemberPointer,
- AddrLabelDiff
+ AddrLabelDiff,
+ Reflection
};
class alignas(uint64_t) LValueBase {
@@ -315,12 +317,21 @@ class APValue {
const AddrLabelExpr* LHSExpr;
const AddrLabelExpr* RHSExpr;
};
+ struct ReflectionData {
+ // OperandKind will eventually have support for
+ // TypeSourceInfo, TemplateReference, NamespaceReference, DeclRefExpr.
+ // Operand stores the opaque pointer of the reflection operand.
+ // Depending on the value of OperandKind, we can perform the
+ // corresponding cast to the associated type.
+ ReflectionKind OperandKind;
+ const void *Operand;
+ };
struct MemberPointerData;
// We ensure elsewhere that Data is big enough for LV and MemberPointerData.
- typedef llvm::AlignedCharArrayUnion<void *, APSInt, APFloat, ComplexAPSInt,
- ComplexAPFloat, Vec, Mat, Arr, StructData,
- UnionData, AddrLabelDiffData>
+ typedef llvm::AlignedCharArrayUnion<
+ void *, APSInt, APFloat, ComplexAPSInt, ComplexAPFloat, Vec, Mat, Arr,
+ StructData, UnionData, AddrLabelDiffData, ReflectionData>
DataType;
static const size_t DataSize = sizeof(DataType);
@@ -415,6 +426,14 @@ class APValue {
: Kind(None), AllowConstexprUnknown(false) {
MakeArray(InitElts, Size);
}
+
+ /// Creates a new Reflection APValue.
+ /// \param OperandKind The kind of reflection.
+ /// \param Operand The entity being reflected.
+ APValue(ReflectionKind OperandKind, const void *Operand) : Kind(None) {
+ MakeReflection(OperandKind, Operand);
+ }
+
/// Creates a new struct APValue.
/// \param UninitStruct Marker. Pass an empty UninitStruct.
/// \param NumBases Number of bases.
@@ -498,6 +517,7 @@ class APValue {
bool isUnion() const { return Kind == Union; }
bool isMemberPointer() const { return Kind == MemberPointer; }
bool isAddrLabelDiff() const { return Kind == AddrLabelDiff; }
+ bool isReflection() const { return Kind == Reflection; }
void dump() const;
void dump(raw_ostream &OS, const ASTContext &Context) const;
@@ -717,6 +737,16 @@ class APValue {
return ((const AddrLabelDiffData *)(const char *)&Data)->RHSExpr;
}
+ ReflectionKind getReflectionOperandKind() const {
+ assert(isReflection() && "Invalid accessor");
+ return ((const ReflectionData *)(const char *)&Data)->OperandKind;
+ }
+
+ const void *getReflectionOpaqueOperand() const {
+ assert(isReflection() && "Invalid accessor");
+ return ((const ReflectionData *)(const char *)&Data)->Operand;
+ }
+
void setInt(APSInt I) {
assert(isInt() && "Invalid accessor");
*(APSInt *)(char *)&Data = std::move(I);
@@ -767,6 +797,11 @@ class APValue {
private:
void DestroyDataAndMakeUninit();
+ void MakeReflection(ReflectionKind OperandKind, const void *Operand) {
+ assert(isAbsent() && "Bad state change");
+ new ((void *)(char *)Data.buffer) ReflectionData{OperandKind, Operand};
+ Kind = Reflection;
+ }
void MakeInt() {
assert(isAbsent() && "Bad state change");
new ((void *)&Data) APSInt(1);
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 7ed6509c3c16c..05dfec8c37586 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1351,6 +1351,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
CanQualType BFloat16Ty;
CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
CanQualType VoidPtrTy, NullPtrTy;
+ CanQualType MetaInfoTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnresolvedTemplateTy,
UnknownAnyTy;
CanQualType BuiltinFnTy;
diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def
index 444be4311a743..ee2f3f0365126 100644
--- a/clang/include/clang/AST/BuiltinTypes.def
+++ b/clang/include/clang/AST/BuiltinTypes.def
@@ -223,6 +223,9 @@ FLOATING_TYPE(Ibm128, Ibm128Ty)
//===- Language-specific types --------------------------------------------===//
+// 'std::meta::info' in C++
+BUILTIN_TYPE(MetaInfo, MetaInfoTy)
+
// This is the type of C++0x 'nullptr'.
BUILTIN_TYPE(NullPtr, NullPtrTy)
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 757f2137c90dc..4ed388877a2ab 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -25,6 +25,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/OperationKinds.h"
+#include "clang/AST/Reflection.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/TemplateBase.h"
@@ -5502,37 +5503,47 @@ class BuiltinBitCastExpr final
/// - a type-id, or
/// - an id-expression.
class CXXReflectExpr : public Expr {
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+private:
// TODO(Reflection): add support for TemplateReference, NamespaceReference and
// DeclRefExpr
- using operand_type = llvm::PointerUnion<const TypeSourceInfo *>;
+ using operand_type = llvm::PointerUnion<TypeSourceInfo *>;
SourceLocation CaretCaretLoc;
+ ReflectionKind Kind;
operand_type Operand;
- CXXReflectExpr(SourceLocation CaretCaretLoc, const TypeSourceInfo *TSI);
+ CXXReflectExpr(ASTContext &C, SourceLocation CaretCaretLoc,
+ TypeSourceInfo *TSI);
CXXReflectExpr(EmptyShell Empty);
public:
static CXXReflectExpr *Create(ASTContext &C, SourceLocation OperatorLoc,
- TypeSourceInfo *TL);
+ TypeSourceInfo *TSI);
static CXXReflectExpr *CreateEmpty(ASTContext &C);
SourceLocation getBeginLoc() const LLVM_READONLY {
return llvm::TypeSwitch<operand_type, SourceLocation>(Operand)
- .Case<const TypeSourceInfo *>(
+ .Case<TypeSourceInfo *>(
[](auto *Ptr) { return Ptr->getTypeLoc().getBeginLoc(); });
}
SourceLocation getEndLoc() const LLVM_READONLY {
return llvm::TypeSwitch<operand_type, SourceLocation>(Operand)
- .Case<const TypeSourceInfo *>(
+ .Case<TypeSourceInfo *>(
[](auto *Ptr) { return Ptr->getTypeLoc().getEndLoc(); });
}
/// Returns location of the '^^'-operator.
SourceLocation getOperatorLoc() const { return CaretCaretLoc; }
+ ReflectionKind getKind() const { return Kind; }
+ void *getOpaqueValue() const { return Operand.getOpaqueValue(); }
+ TypeSourceInfo *getTypeSourceInfo() const {
+ return cast<TypeSourceInfo *>(Operand);
+ }
child_range children() {
// TODO(Reflection)
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index 25ef4c26a9aa1..9a5c683fbf693 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -603,6 +603,31 @@ let Class = PropertyTypeCase<APValue, "LValue"> in {
}]>;
}
+def ReflectionKind : EnumPropertyType<"ReflectionKind">;
+
+let Class = PropertyTypeCase<APValue, "Reflection"> in {
+ def : Property<"reflectionKind", ReflectionKind> {
+ let Read = [{ node.getReflectionOperandKind() }];
+ }
+ def : Property<"reflectionType", QualType> {
+ let Conditional = [{ reflectionKind == ReflectionKind::Type }];
+ let Read = [{
+ QualType::getFromOpaquePtr(node.getReflectionOpaqueOperand())
+ }];
+ }
+ def : Creator<[{
+ switch (reflectionKind) {
+ // TODO(Reflection): Add support for TypeSourceInfo, NamespaceReference
+ // TemplateReference and DeclRefExpr
+ case ReflectionKind::Null:
+ return APValue(reflectionKind, nullptr);
+ case ReflectionKind::Type:
+ return APValue(reflectionKind, (*reflectionType).getAsOpaquePtr());
+ }
+ llvm_unreachable("unimplemented or unknow reflection entities");
+ }]>;
+}
+
// Type cases for DeclarationName.
def : PropertyTypeKind<DeclarationName, DeclarationNameKind,
"node.getNameKind()">;
diff --git a/clang/include/clang/AST/Reflection.h b/clang/include/clang/AST/Reflection.h
new file mode 100644
index 0000000000000..732aefde80885
--- /dev/null
+++ b/clang/include/clang/AST/Reflection.h
@@ -0,0 +1,39 @@
+//===--- Reflection.h - Kind of reflection operands ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the kinds of reflection operands.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_REFLECTION_H
+#define LLVM_CLANG_AST_REFLECTION_H
+
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+
+// TODO(Reflection): Add support for Template, Namespace and DeclRefExpr.
+enum class ReflectionKind { Null, Type };
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ ReflectionKind Kind) {
+ switch (Kind) {
+ case ReflectionKind::Type:
+ OS << "type";
+ break;
+ case ReflectionKind::Null:
+ OS << "null";
+ break;
+ }
+
+ return OS;
+}
+
+} // namespace clang
+
+#endif
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index c9658775f0470..4886db6998b45 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -2766,6 +2766,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isUndeducedAutoType() const; // C++11 auto or
// C++14 decltype(auto)
bool isTypedefNameType() const; // typedef or alias template
+ bool isMetaInfoType() const; // C++26 std::meta::info
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
bool is##Id##Type() const;
@@ -9051,6 +9052,10 @@ inline bool Type::isVoidType() const {
return isSpecificBuiltinType(BuiltinType::Void);
}
+inline bool Type::isMetaInfoType() const {
+ return isSpecificBuiltinType(BuiltinType::MetaInfo);
+}
+
inline bool Type::isHalfType() const {
// FIXME: Should we allow complex __fp16? Probably not.
return isSpecificBuiltinType(BuiltinType::Half);
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 3aba4d261a651..dacc1d3a5d9ea 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -96,6 +96,7 @@ struct TransferrableTargetInfo {
unsigned char FloatWidth, FloatAlign;
unsigned char DoubleWidth, DoubleAlign;
unsigned char LongDoubleWidth, LongDoubleAlign, Float128Align, Ibm128Align;
+ unsigned char MetaInfoWidth, MetaInfoAlign;
unsigned char LargeArrayMinWidth, LargeArrayAlign;
unsigned char LongWidth, LongAlign;
unsigned char LongLongWidth, LongLongAlign;
@@ -828,6 +829,11 @@ class TargetInfo : public TransferrableTargetInfo,
unsigned getIbm128Align() const { return Ibm128Align; }
const llvm::fltSemantics &getIbm128Format() const { return *Ibm128Format; }
+ /// Returns the size of std::meta::info.
+ unsigned getMetaInfoWidth() const { return MetaInfoWidth; }
+ /// eturns the align of std::meta::info.
+ unsigned getMetaInfoAlign() const { return MetaInfoAlign; }
+
/// Return the mangled code of long double.
virtual const char *getLongDoubleMangling() const { return "e"; }
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 671341488278e..e36e6ea29810f 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1155,6 +1155,9 @@ enum PredefinedTypeIDs {
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) PREDEF_TYPE_##Id##_ID,
#include "clang/Basic/HLSLIntangibleTypes.def"
+ /// C++26 std::meta::info type.
+ PREDEF_TYPE_META_INFO_ID,
+
/// The placeholder type for unresolved templates.
PREDEF_TYPE_UNRESOLVED_TEMPLATE,
// Sentinel value. Considered a predefined type but not useable as one.
@@ -1166,7 +1169,7 @@ enum PredefinedTypeIDs {
///
/// Type IDs for non-predefined types will start at
/// NUM_PREDEF_TYPE_IDs.
-const unsigned NUM_PREDEF_TYPE_IDS = 529;
+const unsigned NUM_PREDEF_TYPE_IDS = 530;
// Ensure we do not overrun the predefined types we reserved
// in the enum PredefinedTypeIDs above.
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index 727e5f8c00a10..1849562952fb7 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -374,6 +374,10 @@ APValue::APValue(const APValue &RHS)
MakeAddrLabelDiff();
setAddrLabelDiff(RHS.getAddrLabelDiffLHS(), RHS.getAddrLabelDiffRHS());
break;
+ case Reflection:
+ MakeReflection(RHS.getReflectionOperandKind(),
+ RHS.getReflectionOpaqueOperand());
+ break;
}
}
@@ -429,6 +433,8 @@ void APValue::DestroyDataAndMakeUninit() {
((MemberPointerData *)(char *)&Data)->~MemberPointerData();
else if (Kind == AddrLabelDiff)
((AddrLabelDiffData *)(char *)&Data)->~AddrLabelDiffData();
+ else if (Kind == Reflection)
+ ((ReflectionData *)(char *)&Data)->~ReflectionData();
Kind = None;
AllowConstexprUnknown = false;
}
@@ -438,6 +444,7 @@ bool APValue::needsCleanup() const {
case None:
case Indeterminate:
case AddrLabelDiff:
+ case Reflection:
return false;
case Struct:
case Union:
@@ -486,6 +493,61 @@ static void profileIntValue(llvm::FoldingSetNodeID &ID, const llvm::APInt &V) {
ID.AddInteger((uint32_t)V.extractBitsAsZExtValue(std::min(32u, N - I), I));
}
+/// [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 finds 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
+
+// In particular, this means that e.g. '^^const Alias' is reflection of
+// a type, not an alias. For example:
+//
+// using foo = const int;
+// ^^int // Type
+// ^^const int // Type
+// ^^foo // Alias
+// ^^const foo // Type
+static bool isTypeAliasAsReflectionName(QualType QT) {
+ return QT.getLocalQualifiers() == Qualifiers{};
+}
+
+/// Unwrap reflected type for profiling
+static void profileTypeReflection(llvm::FoldingSetNodeID &ID, QualType QT) {
+ // TODO(Reflection)
+
+ if (isTypeAliasAsReflectionName(QT)) {
+ if (const auto *TDT = QT->getAs<TypedefType>()) {
+ ID.AddBoolean(true);
+ ID.AddPointer(TDT->getDecl()->getCanonicalDecl());
+ return;
+ }
+ }
+
+ ID.AddBoolean(false);
+ QT.getCanonicalType().Profile(ID);
+}
+
+static void profileReflection(llvm::FoldingSetNodeID &ID, APValue V) {
+ ID.AddInteger(static_cast<int>(V.getReflectionOperandKind()));
+ switch (V.getReflectionOperandKind()) {
+ case ReflectionKind::Null:
+ return;
+ case ReflectionKind::Type: {
+ const TypeSourceInfo *Info =
+ static_cast<const TypeSourceInfo *>(V.getReflectionOpaqueOperand());
+ profileTypeReflection(ID, Info->getType());
+ return;
+ }
+ }
+ assert(false && "unknown or unimplemented reflection entities");
+}
+
void APValue::Profile(llvm::FoldingSetNodeID &ID) const {
// Note that our profiling assumes that only APValues of the same type are
// ever compared. As a result, we don't consider collisions that could only
@@ -632,6 +694,9 @@ void APValue::Profile(llvm::FoldingSetNodeID &ID) const {
for (const CXXRecordDecl *D : getMemberPointerPath())
ID.AddPointer(D);
return;
+ case Reflection:
+ profileReflection(ID, *this);
+ return;
}
llvm_unreachable("Unknown APValue kind!");
@@ -986,6 +1051,19 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy,
Out << " - ";
Out << "&&" << getAddrLabelDiffRHS()->getLabel()->getName();
return;
+ case APValue::Reflection:
+ switch (getReflectionOperandKind()) {
+ case ReflectionKind::Null:
+ Out << "std::meta::info{}";
+ break;
+ case ReflectionKind::Type: {
+ const auto *TInfo =
+ static_cast<const TypeSourceInfo *>(getReflectionOpaqueOperand());
+ Out << "^^" << TInfo->getType().stream(Policy);
+ break;
+ }
+ }
+ return;
}
llvm_unreachable("Unknown APValue kind!");
}
@@ -1176,6 +1254,7 @@ LinkageInfo LinkageComputer::getLVForValue(const APValue &V,
case APValue::ComplexInt:
case APValue::ComplexFloat:
case APValue::Vector:
+ case APValue::Reflection:
case APValue::Matrix:
break;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 2228811546c0f..c94598662915d 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1511,6 +1511,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
// nullptr type (C++0x 2.14.7)
InitBuiltinType(NullPtrTy, BuiltinType::NullPtr);
+ // std::meta::info type (C++26 21.4.1)
+ InitBuiltinType(MetaInfoTy, BuiltinType::MetaInfo);
+
// half type (OpenCL 6.1.1.1) / ARM NEON __fp16
InitBuiltinType(HalfTy, BuiltinType::Half);
@@ -2366,6 +2369,10 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Width = Target->getPointerWidth(LangAS::Default);
Align = Target->getPointerAlign(LangAS::Default);
break;
+ case BuiltinType::MetaInfo:
+ Width = Target->getMetaInfoWidth();
+ Align = Target->getMetaInfoAlign();
+ break;
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
@@ -3568,6 +3575,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
case BuiltinType::VectorPair:
case BuiltinType::DMR1024:
case BuiltinType::DMR2048:
+ case BuiltinType::MetaInfo:
OS << "?";
return;
@@ -9325,6 +9333,7 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C,
case BuiltinType::OCLReserveID:
case BuiltinType::OCLSampler:
case BuiltinType::Dependent:
+ case BuiltinType::MetaInfo:
#define PPC_VECTOR_TYPE(Name, Id, Size) \
case BuiltinType::Id:
#include "clang/Basic/PPCTypes.def"
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index db7d223d56af3..7e726eb155d38 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -686,6 +686,7 @@ namespace clang {
ExpectedStmt VisitCXXThisExpr(CXXThisExpr *E);
ExpectedStmt VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
ExpectedStmt VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
+ ExpectedStmt VisitCXXReflectExpr(CXXReflectExpr *E);
ExpectedStmt VisitMemberExpr(MemberExpr *E);
ExpectedStmt VisitCallExpr(CallExpr *E);
ExpectedStmt VisitLambdaExpr(LambdaExpr *LE);
@@ -8861,6 +8862,16 @@ ExpectedStmt ASTNodeImporter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
*ToTypeOrErr, *ToLocationOrErr);
}
+ExpectedStmt ASTNodeImporter::VisitCXXReflectExpr(CXXReflectExpr *E) {
+ Error Err = Error::success();
+ auto ToOperatorLoc = importChecked(Err, E->getOperatorLoc());
+ auto ToTSI = importChecked(Err, E->getTypeSourceInfo());
+ if (Err)
+ return std::move(Err);
+
+ return CXXReflectExpr::Create(Importer.getToContext(), ToOperatorLoc, ToTSI);
+}
+
ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) {
Error Err = Error::success();
auto ToBase = importChecked(Err, E->getBase());
@@ -10873,7 +10884,7 @@ ASTNodeImporter::ImportAPValue(const APValue &FromValue) {
}
break;
}
- case APValue::LValue:
+ case APValue::LValue: {
APValue::LValueBase Base;
QualType FromElemTy;
if (FromValue.getLValueBase()) {
@@ -10944,6 +10955,27 @@ ASTNodeImporter::ImportAPValue(const APValue &FromValue) {
} else
Result.setLValue(Base, Offset, APValue::NoLValuePath{},
FromValue.isNullPointer());
+ break;
+ }
+ case APValue::Reflection: {
+ switch (FromValue.getReflectionOperandKind()) {
+ case ReflectionKind::Null:
+ Result = APValue(ReflectionKind::Null, nullptr);
+ break;
+ case ReflectionKind::Type: {
+ const auto *FromTSI = static_cast<const TypeSourceInfo *>(
+ FromValue.getReflectionOpaqueOperand());
+ QualType ImpType = importChecked(Err, FromTSI->getType());
+ if (Err)
+ return std::move(Err);
+ TypeSourceInfo *ToTSI =
+ Importer.ToContext.getTrivialTypeSourceInfo(ImpType);
+ Result = APValue(ReflectionKind::Type, ToTSI);
+ break;
+ }
+ }
+ break;
+ }
}
if (Err)
return std::move(Err);
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 35667a9132680..a698c35871d2e 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -4521,6 +4521,23 @@ bool Compiler<Emitter>::VisitObjCArrayLiteral(const ObjCArrayLiteral *E) {
return this->emitError(E);
}
+template <class Emitter>
+bool Compiler<Emitter>::VisitCXXReflectExpr(const CXXReflectExpr *E) {
+ if (DiscardResult)
+ return true;
+
+ switch (E->getKind()) {
+ case ReflectionKind::Type: {
+ APValue Result(ReflectionKind::Type, E->getOpaqueValue());
+ return this->emitReflectValue(E->getKind(), E->getOpaqueValue(), E);
+ }
+ case ReflectionKind::Null:
+ llvm_unreachable("A null reflection should not reach here");
+ }
+
+ return false;
+}
+
template <class Emitter>
bool Compiler<Emitter>::VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
assert(Ctx.getLangOpts().CPlusPlus);
@@ -5038,6 +5055,8 @@ bool Compiler<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
auto Sem = Ctx.getASTContext().getFixedPointSemantics(QT);
return this->emitConstFixedPoint(FixedPoint::zero(Sem), E);
}
+ case PT_Reflect:
+ return this->emitReflectValue(ReflectionKind::Null, nullptr, E);
}
llvm_unreachable("unknown primitive type");
}
@@ -5267,6 +5286,7 @@ bool Compiler<Emitter>::emitConst(T Value, PrimType Ty, SourceInfo Info) {
case PT_IntAP:
case PT_IntAPS:
case PT_FixedPoint:
+ case PT_Reflect:
llvm_unreachable("Invalid integral type");
break;
}
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 9eb8069496099..3051ad9399266 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -232,6 +232,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
bool VisitCXXTypeidExpr(const CXXTypeidExpr *E);
bool VisitObjCDictionaryLiteral(const ObjCDictionaryLiteral *E);
bool VisitObjCArrayLiteral(const ObjCArrayLiteral *E);
+ bool VisitCXXReflectExpr(const CXXReflectExpr *E);
bool VisitDesignatedInitUpdateExpr(const DesignatedInitUpdateExpr *E);
// Statements.
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index b913d2a9f539c..673c6adf5f96b 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -539,6 +539,9 @@ OptPrimType Context::classify(QualType T) const {
if (T->isFixedPointType())
return PT_FixedPoint;
+ if (T->isMetaInfoType())
+ return PT_Reflect;
+
// Vector and complex types get here.
return std::nullopt;
}
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp
index fb41c98dd68cb..1118267b61295 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -16,6 +16,7 @@
#include "Pointer.h"
#include "PrimType.h"
#include "Record.h"
+#include "Reflect.h"
#include "Source.h"
#include "clang/AST/ExprCXX.h"
diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp
index 4caf830a0a1b4..4a2e47d427f91 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -318,6 +318,8 @@ static const char *primTypeToString(PrimType T) {
return "MemberPtr";
case PT_FixedPoint:
return "FixedPoint";
+ case PT_Reflect:
+ return "Reflect";
}
llvm_unreachable("Unhandled PrimType");
}
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index f59485ec306e4..ebe4a7256c7fd 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -3230,7 +3230,7 @@ constexpr bool OpReturns(Opcode Op) {
Op == OP_RetSint64 || Op == OP_RetUint64 || Op == OP_RetIntAP ||
Op == OP_RetIntAPS || Op == OP_RetBool || Op == OP_RetFixedPoint ||
Op == OP_RetPtr || Op == OP_RetMemberPtr || Op == OP_RetFloat ||
- Op == OP_EndSpeculation;
+ Op == OP_RetReflect || Op == OP_EndSpeculation;
}
#if USE_TAILCALLS
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 405f4a29ec982..63f6ffc74c237 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -29,6 +29,7 @@
#include "MemberPointer.h"
#include "PrimType.h"
#include "Program.h"
+#include "Reflect.h"
#include "State.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
@@ -4090,6 +4091,12 @@ inline bool CheckDestruction(InterpState &S, CodePtr OpPC) {
return checkDestructor(S, OpPC, Ptr);
}
+inline bool ReflectValue(InterpState &S, CodePtr OpPC, ReflectionKind Kind,
+ const void *Operand) {
+ S.Stk.push<Reflect>(Kind, Operand);
+ return true;
+}
+
inline bool IsBaseClass(InterpState &S) {
S.Stk.push<bool>(S.Stk.peek<Pointer>().isBaseClass());
return true;
diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
index f136301c02912..35edb5988b817 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
@@ -515,7 +515,7 @@ using PrimTypeVariant =
Char<false>, Char<true>, Integral<16, false>,
Integral<16, true>, Integral<32, false>, Integral<32, true>,
Integral<64, false>, Integral<64, true>, IntegralAP<true>,
- IntegralAP<false>, Boolean, Floating>;
+ IntegralAP<false>, Boolean, Floating, Reflect>;
// NB: This implementation isn't exactly ideal, but:
// 1) We can't just do a bitcast here since we need to be able to
diff --git a/clang/lib/AST/ByteCode/InterpStack.h b/clang/lib/AST/ByteCode/InterpStack.h
index 2c02979ee6eec..a83d173e0eb16 100644
--- a/clang/lib/AST/ByteCode/InterpStack.h
+++ b/clang/lib/AST/ByteCode/InterpStack.h
@@ -17,6 +17,7 @@
#include "IntegralAP.h"
#include "MemberPointer.h"
#include "PrimType.h"
+#include "Reflect.h"
namespace clang {
namespace interp {
@@ -203,6 +204,8 @@ class InterpStack final {
return PT_MemberPtr;
else if constexpr (std::is_same_v<T, FixedPoint>)
return PT_FixedPoint;
+ else if constexpr (std::is_same_v<T, Reflect>)
+ return PT_Reflect;
llvm_unreachable("unknown type push()'ed into InterpStack");
}
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp
index f6338cda56e34..ff1b6bada6223 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -10,6 +10,7 @@
#include "InterpFrame.h"
#include "InterpStack.h"
#include "Program.h"
+#include "Reflect.h"
#include "State.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index c2f0114c81957..891fb423a9d77 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -31,6 +31,7 @@ def Float : Type;
def Ptr : Type;
def MemberPtr : Type;
def FixedPoint : Type;
+def Reflect : Type;
//===----------------------------------------------------------------------===//
// Types transferred to the interpreter.
@@ -71,6 +72,8 @@ def ArgDesc : ArgType { let Name = "const Descriptor *"; }
def ArgPrimType : ArgType { let Name = "PrimType"; }
def ArgEnumDecl : ArgType { let Name = "const EnumDecl *"; }
def ArgTypePtr : ArgType { let Name = "const Type *"; }
+def ArgVoidPtr : ArgType { let Name = "const void *"; }
+def ArgReflectionKind : ArgType { let Name = "ReflectionKind"; }
//===----------------------------------------------------------------------===//
// Classes of types instructions operate on.
@@ -121,7 +124,7 @@ def NonPtrTypeClass : TypeClass {
}
def AllTypeClass : TypeClass {
- let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types, FloatTypeClass.Types);
+ let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types, FloatTypeClass.Types, [Reflect]);
}
def ComparableTypeClass : TypeClass {
@@ -368,6 +371,10 @@ def CastMemberPtrDerivedPop : Opcode {
let NeedsOpPC = 0;
}
+def ReflectValue : Opcode {
+ let Args = [ArgReflectionKind, ArgVoidPtr];
+}
+
def FinishInitPop : SuccessOpcode;
def FinishInit : SuccessOpcode;
def FinishInitActivate : SuccessOpcode;
diff --git a/clang/lib/AST/ByteCode/PrimType.cpp b/clang/lib/AST/ByteCode/PrimType.cpp
index 923233e5fb13a..0ba95bab5c6b5 100644
--- a/clang/lib/AST/ByteCode/PrimType.cpp
+++ b/clang/lib/AST/ByteCode/PrimType.cpp
@@ -14,6 +14,7 @@
#include "IntegralAP.h"
#include "MemberPointer.h"
#include "Pointer.h"
+#include "Reflect.h"
using namespace clang;
using namespace clang::interp;
diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h
index 8f725942fedb9..ce10ebf4835ec 100644
--- a/clang/lib/AST/ByteCode/PrimType.h
+++ b/clang/lib/AST/ByteCode/PrimType.h
@@ -26,6 +26,7 @@ class Boolean;
class Floating;
class MemberPointer;
class FixedPoint;
+class Reflect;
template <bool Signed> class IntegralAP;
template <bool Signed> class Char;
template <unsigned Bits, bool Signed> class Integral;
@@ -47,6 +48,7 @@ enum PrimType : uint8_t {
PT_Float = 12,
PT_Ptr = 13,
PT_MemberPtr = 14,
+ PT_Reflect = 15,
};
constexpr bool isIntegerOrBoolType(PrimType T) { return T <= PT_Bool; }
@@ -193,6 +195,9 @@ template <> struct PrimConv<PT_MemberPtr> {
template <> struct PrimConv<PT_FixedPoint> {
using T = FixedPoint;
};
+template <> struct PrimConv<PT_Reflect> {
+ using T = Reflect;
+};
/// Returns the size of a primitive type in bytes.
size_t primSize(PrimType Type);
@@ -238,6 +243,7 @@ static inline bool aligned(const void *P) {
TYPE_SWITCH_CASE(PT_Ptr, B) \
TYPE_SWITCH_CASE(PT_MemberPtr, B) \
TYPE_SWITCH_CASE(PT_FixedPoint, B) \
+ TYPE_SWITCH_CASE(PT_Reflect, B) \
} \
} while (0)
diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp
index 378a190184be9..5f0ca50a41f4c 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -12,6 +12,7 @@
#include "Function.h"
#include "Integral.h"
#include "PrimType.h"
+#include "Reflect.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h
index b0ef993258637..764e5ee4b5c70 100644
--- a/clang/lib/AST/ByteCode/Program.h
+++ b/clang/lib/AST/ByteCode/Program.h
@@ -17,6 +17,7 @@
#include "Pointer.h"
#include "PrimType.h"
#include "Record.h"
+#include "Reflect.h"
#include "Source.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Allocator.h"
diff --git a/clang/lib/AST/ByteCode/Reflect.h b/clang/lib/AST/ByteCode/Reflect.h
new file mode 100644
index 0000000000000..dcd00a3bad782
--- /dev/null
+++ b/clang/lib/AST/ByteCode/Reflect.h
@@ -0,0 +1,60 @@
+//===--- Boolean.h - Wrapper for boolean types for the VM -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_REFLECT_H
+#define LLVM_CLANG_AST_INTERP_REFLECT_H
+
+#include "clang/AST/APValue.h"
+#include "clang/AST/ComparisonCategories.h"
+#include "clang/AST/Reflection.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+
+namespace clang {
+namespace interp {
+
+class Reflect final {
+private:
+ ReflectionKind Kind;
+ const void *Operand;
+
+public:
+ Reflect() : Kind(ReflectionKind::Null), Operand(nullptr) {}
+ Reflect(ReflectionKind Kind, const void *Operand)
+ : Kind(Kind), Operand(Operand) {}
+
+ ComparisonCategoryResult compare(const Reflect &RHS) const {
+ llvm::FoldingSetNodeID LID, RID;
+ APValue(Kind, Operand).Profile(LID);
+ APValue(RHS.Kind, RHS.Operand).Profile(RID);
+
+ if (LID == RID)
+ return ComparisonCategoryResult::Equal;
+ return ComparisonCategoryResult::Unordered;
+ }
+
+ void print(llvm::raw_ostream &OS) const {
+ OS << "Reflect(" << Kind << ", " << Operand << ")";
+ }
+ APValue toAPValue(const ASTContext &Ctx) const {
+ return APValue(Kind, Operand);
+ }
+};
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Reflect &R) {
+ R.print(OS);
+ return OS;
+}
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 6c1cde6540d85..f77999d8bada9 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/LambdaCapture.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/Reflection.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
@@ -1934,15 +1935,15 @@ TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C,
CXXReflectExpr::CXXReflectExpr(EmptyShell Empty)
: Expr(CXXReflectExprClass, Empty) {}
-CXXReflectExpr::CXXReflectExpr(SourceLocation CaretCaretLoc,
- const TypeSourceInfo *TSI)
- : Expr(CXXReflectExprClass, TSI->getType(), VK_PRValue, OK_Ordinary),
- CaretCaretLoc(CaretCaretLoc), Operand(TSI) {}
+CXXReflectExpr::CXXReflectExpr(ASTContext &C, SourceLocation CaretCaretLoc,
+ TypeSourceInfo *TSI)
+ : Expr(CXXReflectExprClass, C.MetaInfoTy, VK_PRValue, OK_Ordinary),
+ CaretCaretLoc(CaretCaretLoc), Kind(ReflectionKind::Type), Operand(TSI) {}
CXXReflectExpr *CXXReflectExpr::Create(ASTContext &C,
SourceLocation CaretCaretLoc,
TypeSourceInfo *TSI) {
- return new (C) CXXReflectExpr(CaretCaretLoc, TSI);
+ return new (C) CXXReflectExpr(C, CaretCaretLoc, TSI);
}
CXXReflectExpr *CXXReflectExpr::CreateEmpty(ASTContext &C) {
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 574dd8b04e779..30086822583d8 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -48,6 +48,7 @@
#include "clang/AST/OSLog.h"
#include "clang/AST/OptionalDiagnostic.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Reflection.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
@@ -2644,6 +2645,7 @@ static bool HandleConversionToBool(const APValue &Val, bool &Result) {
case APValue::Struct:
case APValue::Union:
case APValue::AddrLabelDiff:
+ case APValue::Reflection:
return false;
}
@@ -7984,7 +7986,8 @@ class APValueToBufferConverter {
case APValue::Matrix:
case APValue::Union:
case APValue::MemberPointer:
- case APValue::AddrLabelDiff: {
+ case APValue::AddrLabelDiff:
+ case APValue::Reflection: {
Info.FFDiag(BCE->getBeginLoc(),
diag::note_constexpr_bit_cast_unsupported_type)
<< Ty;
@@ -11220,6 +11223,57 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
return true;
}
+
+//===----------------------------------------------------------------------===//
+// Reflection expression evaluation
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ReflectionEvaluator : public ExprEvaluatorBase<ReflectionEvaluator> {
+
+ using BaseType = ExprEvaluatorBase<ReflectionEvaluator>;
+
+ APValue &Result;
+
+public:
+ ReflectionEvaluator(EvalInfo &E, APValue &Result)
+ : ExprEvaluatorBaseTy(E), Result(Result) {}
+
+ bool Success(const APValue &V, const Expr *E) {
+ Result = V;
+ return true;
+ }
+
+ bool VisitCXXReflectExpr(const CXXReflectExpr *E);
+ bool ZeroInitialization(const Expr *E);
+};
+
+bool ReflectionEvaluator::VisitCXXReflectExpr(const CXXReflectExpr *E) {
+ switch (E->getKind()) {
+ case ReflectionKind::Null: {
+ APValue Result(ReflectionKind::Null, /*Operand=*/nullptr);
+ return Success(Result, E);
+ }
+ case ReflectionKind::Type: {
+ APValue Result(ReflectionKind::Type, E->getOpaqueValue());
+ return Success(Result, E);
+ }
+ }
+ llvm_unreachable("invalid reflection");
+}
+
+bool ReflectionEvaluator::ZeroInitialization(const Expr *E) {
+ Result = APValue(ReflectionKind::Null, /*Operand=*/nullptr);
+ return true;
+}
+
+} // end anonymous namespace
+
+static bool EvaluateReflection(const Expr *E, APValue &Result, EvalInfo &Info) {
+ assert(E->isPRValue() && E->getType()->isMetaInfoType());
+ return ReflectionEvaluator(Info, Result).Visit(E);
+}
+
//===----------------------------------------------------------------------===//
// Member Pointer Evaluation
//===----------------------------------------------------------------------===//
@@ -16319,6 +16373,7 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
#include "clang/Basic/AMDGPUTypes.def"
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
#include "clang/Basic/HLSLIntangibleTypes.def"
+ case BuiltinType::MetaInfo:
return GCCTypeClass::None;
case BuiltinType::Dependent:
@@ -19431,6 +19486,23 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
return Success(CmpResult::Equal, E);
}
+ if (LHSTy->isMetaInfoType() && RHSTy->isMetaInfoType()) {
+ APValue LHSValue, RHSValue;
+ llvm::FoldingSetNodeID LID, RID;
+ if (!Evaluate(LHSValue, Info, E->getLHS()))
+ return false;
+ LHSValue.Profile(LID);
+
+ if (!Evaluate(RHSValue, Info, E->getRHS()))
+ return false;
+ RHSValue.Profile(RID);
+
+ if (LID == RID)
+ return Success(CmpResult::Equal, E);
+ else
+ return Success(CmpResult::Unequal, E);
+ }
+
return DoAfter();
}
@@ -21607,6 +21679,9 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
} else if (T->isIntegralOrEnumerationType()) {
if (!IntExprEvaluator(Info, Result).Visit(E))
return false;
+ } else if (T->isMetaInfoType()) {
+ if (!EvaluateReflection(E, Result, Info))
+ return false;
} else if (T->hasPointerRepresentation()) {
LValue LV;
if (!EvaluatePointer(E, LV, Info))
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 172a19f8f3537..e649369b61e04 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -575,6 +575,7 @@ class CXXNameMangler {
void mangleFloatLiteral(QualType T, const llvm::APFloat &V);
void mangleFixedPointLiteral();
void mangleNullPointer(QualType T);
+ void mangleReflection(ReflectionKind Kind, const void *OpaqueOperand);
void mangleMemberExprBase(const Expr *base, bool isArrow);
void mangleMemberExpr(const Expr *base, bool isArrow,
@@ -1273,6 +1274,56 @@ void CXXNameMangler::mangleNullPointer(QualType T) {
Out << "0E";
}
+void CXXNameMangler::mangleReflection(ReflectionKind Kind,
+ const void *OpaqueOperand) {
+ // https://github.com/itanium-cxx-abi/cxx-abi/issues/208
+ // TODO(Reflection): add support for remaining items in the grammar below
+
+ // <reflection> ::= nu # null reflection
+ // ::= vl <expression> # value
+ // ::= ob <expression> # object
+ // ::= vr <variable name> # variable
+ // ::= sb <sb name> # structured binding
+ // ::= fn <function encoding> # function
+ // ::= pa [ <nonnegative number> ] _ <encoding> # function
+ // parameter
+ // ::= en <prefix> <unqualified-name> # enumerator
+ // ::= an [ <nonnegative number> ] _ # annotation
+ // ::= ta <alias prefix> # type alias
+ // ::= ty <type> # type
+ // ::= dm <prefix> <unqualified-name> # non-static data
+ // member
+ // ::= un <prefix> [ <nonnegative number> ] _ # unnamed bit-field
+ // ::= ct [ <prefix> ] <unqualified-name> # class template
+ // ::= ft [ <prefix> ] <unqualified-name> # function template
+ // ::= vt [ <prefix> ] <unqualified-name> # variable template
+ // ::= at [ <prefix> ] <unqualified-name> # alias template
+ // ::= co [ <prefix> ] <unqualified-name> # concept
+ // ::= na [ <prefix> ] <unqualified-name> # namespace alias
+ // ::= ns [ <prefix> ] <unqualified-name> # namespace
+ // ::= ng # ^^::
+ // ::= ba [ <nonnegative number> ] _ <type> # direct base class
+ // relationship
+ // ::= ds <type> _ [ <unqualified-name> ] _
+ // [ <alignment number> ] _ [ <bit-width number> ] _
+ // [ n ] # data member
+ // description
+
+ Out << "LDm";
+ switch (Kind) {
+ case ReflectionKind::Null:
+ Out << "nu";
+ break;
+ case ReflectionKind::Type: {
+ const auto *TSI = static_cast<const TypeSourceInfo *>(OpaqueOperand);
+ Out << "ty";
+ mangleType(TSI->getType());
+ break;
+ }
+ }
+ Out << 'E';
+}
+
void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
if (Value.isSigned() && Value.isNegative()) {
Out << 'n';
@@ -3148,10 +3199,12 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
// UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits)
// UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits)
// ::= Dh # IEEE 754r half-precision floating point (16 bits)
- // ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits);
+ // ::= DF <number> _ # ISO/IEC TS 18661 binary floating point
+ // type _FloatN (N bits);
// ::= Di # char32_t
// ::= Ds # char16_t
// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+ // ::= Dm # std::meta::info (i.e., decltype(^^int))
// ::= [DS] DA # N1169 fixed-point [_Sat] T _Accum
// ::= [DS] DR # N1169 fixed-point [_Sat] T _Fract
// ::= u <source-name> # vendor extended type
@@ -3420,6 +3473,10 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
Out << TI->getIbm128Mangling();
break;
}
+ case BuiltinType::MetaInfo:
+ // https://github.com/itanium-cxx-abi/cxx-abi/issues/208
+ Out << "Dm";
+ break;
case BuiltinType::NullPtr:
Out << "Dn";
break;
@@ -4936,6 +4993,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
// ::= L <pointer type> 0 E # null pointer template argument
// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C99); not used by clang
// ::= L <mangled-name> E # external name
+ // ::= LDm <reflection> E # C++26 reflection value
// clang-format on
QualType ImplicitlyConvertedToType;
@@ -5015,8 +5073,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
goto recurse;
case Expr::CXXReflectExprClass: {
- // TODO(Reflection): implement this after introducing std::meta::info
- assert(false && "unimplemented");
+ const CXXReflectExpr *RE = cast<CXXReflectExpr>(E);
+ mangleReflection(RE->getKind(), RE->getOpaqueValue());
break;
}
@@ -6554,6 +6612,9 @@ static bool isZeroInitialized(QualType T, const APValue &V) {
case APValue::MemberPointer:
return !V.getMemberPointerDecl();
+
+ case APValue::Reflection:
+ return !V.getReflectionOpaqueOperand();
}
llvm_unreachable("Unhandled APValue::ValueKind enum");
@@ -6950,6 +7011,12 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V,
break;
}
+ case APValue::Reflection: {
+ mangleReflection(V.getReflectionOperandKind(),
+ V.getReflectionOpaqueOperand());
+ break;
+ }
+
case APValue::MemberPointer:
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
if (!V.getMemberPointerDecl()) {
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 59732ff0fed11..06abe01553b43 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -2168,6 +2168,11 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
Error("template argument (value type: fixed point)");
return;
}
+
+ case APValue::Reflection: {
+ Error("template argument (value type: reflection)");
+ return;
+ }
}
}
diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp
index 17f5ee5dee3d1..70d56c96f5bdf 100644
--- a/clang/lib/AST/NSAPI.cpp
+++ b/clang/lib/AST/NSAPI.cpp
@@ -471,6 +471,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::OMPArrayShaping:
case BuiltinType::OMPIterator:
case BuiltinType::BFloat16:
+ case BuiltinType::MetaInfo:
break;
}
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 9a97d52fd3020..6647b5975e7d0 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2635,8 +2635,15 @@ void StmtPrinter::VisitCXXUnresolvedConstructExpr(
}
void StmtPrinter::VisitCXXReflectExpr(CXXReflectExpr *S) {
- // TODO(Reflection): Implement this.
- assert(false && "not implemented yet");
+ // TODO(Reflection): add support for the remaining reflection kinds.
+ OS << "^^";
+ switch (S->getKind()) {
+ case ReflectionKind::Null:
+ break;
+ case ReflectionKind::Type:
+ S->getTypeSourceInfo()->getType().print(OS, Policy);
+ break;
+ }
}
void StmtPrinter::VisitCXXDependentScopeMemberExpr(
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 5d724e9d1d91e..67b268af2f4c8 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -616,6 +616,7 @@ static bool isSimpleAPValue(const APValue &Value) {
case APValue::LValue:
case APValue::MemberPointer:
case APValue::AddrLabelDiff:
+ case APValue::Reflection:
return true;
case APValue::Vector:
case APValue::Array:
@@ -875,6 +876,21 @@ void TextNodeDumper::Visit(const APValue &Value, QualType Ty) {
OS << " - ";
OS << "&&" << Value.getAddrLabelDiffRHS()->getLabel()->getName();
return;
+ case APValue::Reflection:
+ OS << "Reflection ";
+ switch (Value.getReflectionOperandKind()) {
+ case ReflectionKind::Null:
+ OS << "std::meta::info{}";
+ break;
+ case ReflectionKind::Type: {
+ OS << "^^";
+ const TypeSourceInfo *TSI = static_cast<const TypeSourceInfo *>(
+ Value.getReflectionOpaqueOperand());
+ TSI->getType().print(OS, PrintPolicy);
+ break;
+ }
+ }
+ return;
}
llvm_unreachable("Unknown APValue kind!");
}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 42d148715bc40..2f94b4664785e 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3171,6 +3171,13 @@ bool Type::isLiteralType(const ASTContext &Ctx) const {
return true;
}
+ // C++26 [basic.types]p9:
+ // -- std::meta::info is a scalar type
+ // C++26 [basic.types]p10:
+ // -- a scalar type is a literal type
+ if (isMetaInfoType())
+ return true;
+
// We treat _Atomic T as a literal type if T is a literal type.
if (const auto *AT = BaseTy->getAs<AtomicType>())
return AT->getValueType()->isLiteralType(Ctx);
@@ -3546,6 +3553,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
return "unsigned _Accum";
case ULongAccum:
return "unsigned long _Accum";
+ case BuiltinType::MetaInfo:
+ return "std::meta::info";
case BuiltinType::ShortFract:
return "short _Fract";
case BuiltinType::Fract:
@@ -5260,6 +5269,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
#include "clang/Basic/HLSLIntangibleTypes.def"
case BuiltinType::BuiltinFn:
case BuiltinType::NullPtr:
+ case BuiltinType::MetaInfo:
case BuiltinType::IncompleteMatrixIdx:
case BuiltinType::ArraySection:
case BuiltinType::OMPArrayShaping:
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index 7e72a85136966..e8c018eb92e23 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -426,6 +426,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::ArraySection:
case BuiltinType::OMPArrayShaping:
case BuiltinType::OMPIterator:
+ case BuiltinType::MetaInfo:
return TST_unspecified;
}
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 46b5bdecb9c40..e429f4a76e564 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -126,6 +126,8 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
LongDoubleAlign = 64;
Float128Align = 128;
Ibm128Align = 128;
+ MetaInfoWidth = 64;
+ MetaInfoAlign = 8;
LargeArrayMinWidth = 0;
LargeArrayAlign = 0;
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0;
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 7421733efcc24..42ad4673b792b 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1216,6 +1216,8 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::SatULongFract:
Encoding = llvm::dwarf::DW_ATE_unsigned_fixed;
break;
+ case BuiltinType::MetaInfo:
+ llvm_unreachable("std::meta::info is consteval-only type");
}
BTName = BT->getName(CGM.getLangOpts());
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 257de0145855b..f865022259978 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2752,6 +2752,8 @@ ConstantEmitter::tryEmitPrivate(const APValue &Value, QualType DestType,
}
case APValue::MemberPointer:
return CGM.getCXXABI().EmitMemberPointer(Value, DestType);
+ case APValue::Reflection:
+ llvm_unreachable("std::meta::info is consteval-only type");
}
llvm_unreachable("Unknown APValue kind");
}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index d1119e6c00d14..da4f27b82e475 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6366,6 +6366,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
if (getLangOpts().OpenCL && ASTTy->isSamplerT())
return;
+ // TODO(Reflection): add support for consteval-only types.
+
// HLSL default buffer constants will be emitted during HLSLBufferDecl codegen
if (getLangOpts().HLSL &&
D->getType().getAddressSpace() == LangAS::hlsl_constant)
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index 55fe216580314..f559ac76f7984 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -487,6 +487,13 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
ResultType = llvm::PointerType::getUnqual(getLLVMContext());
break;
+ case BuiltinType::MetaInfo:
+ // FIXME(Reflection): once consteval-only types are supported,
+ // make this an llvm_unreachable instead because reflection
+ // should not reach here
+ ResultType = llvm::IntegerType::get(getLLVMContext(), 64);
+ break;
+
case BuiltinType::UInt128:
case BuiltinType::Int128:
ResultType = llvm::IntegerType::get(getLLVMContext(), 128);
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index b17478cb7ffde..80696c846c816 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3813,6 +3813,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::SatUFract:
case BuiltinType::SatULongFract:
case BuiltinType::BFloat16:
+ case BuiltinType::MetaInfo:
return false;
case BuiltinType::Dependent:
diff --git a/clang/lib/CodeGen/QualTypeMapper.cpp b/clang/lib/CodeGen/QualTypeMapper.cpp
index 31d9250a48ec9..f41e1fa6c9763 100644
--- a/clang/lib/CodeGen/QualTypeMapper.cpp
+++ b/clang/lib/CodeGen/QualTypeMapper.cpp
@@ -156,6 +156,9 @@ QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
return Builder.getIntegerType(1, getTypeAlign(QT), /*Signed=*/false,
/*IsBitInt=*/false);
+ case BuiltinType::MetaInfo:
+ llvm::reportFatalInternalError("std::meta::info is consteval-only type");
+
case BuiltinType::Char_S:
case BuiltinType::Char_U:
case BuiltinType::SChar:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index b844670543a55..5f0a275c67756 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13040,6 +13040,13 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
*CCT, Loc, ComparisonCategoryUsage::OperatorInExpression);
};
+ if (LHSType->isMetaInfoType() && RHSType->isMetaInfoType()) {
+ if (!BinaryOperator::isEqualityOp(Opc)) {
+ return InvalidOperands(Loc, LHS, RHS);
+ }
+ return computeResultTy();
+ }
+
if (!IsOrdered && LHSIsNull != RHSIsNull) {
bool IsEquality = Opc == BO_EQ;
if (RHSIsNull)
@@ -16392,7 +16399,11 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
<< resultType << Input.get()->getSourceRange());
}
- if (resultType->isScalarType() && !isScopedEnumerationType(resultType)) {
+ if (resultType->isScalarType() && !isScopedEnumerationType(resultType) &&
+ !resultType->isMetaInfoType()) {
+ // before C++26, scalar types are contextually converted to bool,
+ // std::meta::info is a scalar type but not an arithmetic type.
+
// C99 6.5.3.3p1: ok, fallthrough;
if (Context.getLangOpts().CPlusPlus) {
// C++03 [expr.unary.op]p8, C++0x [expr.unary.op]p9:
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index eafda32198f11..a2d32e7406982 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -9108,6 +9108,10 @@ class BuiltinCandidateTypeSet {
/// candidate set.
bool HasNullPtrType;
+ /// A flag indicating whether the reflection type was present in the
+ /// candidate set.
+ bool HasReflectionType;
+
/// Sema - The semantic analysis instance where we are building the
/// candidate type set.
Sema &SemaRef;
@@ -9124,11 +9128,9 @@ class BuiltinCandidateTypeSet {
typedef TypeSet::iterator iterator;
BuiltinCandidateTypeSet(Sema &SemaRef)
- : HasNonRecordTypes(false),
- HasArithmeticOrEnumeralTypes(false),
- HasNullPtrType(false),
- SemaRef(SemaRef),
- Context(SemaRef.Context) { }
+ : HasNonRecordTypes(false), HasArithmeticOrEnumeralTypes(false),
+ HasNullPtrType(false), HasReflectionType(false), SemaRef(SemaRef),
+ Context(SemaRef.Context) {}
void AddTypesConvertedFrom(QualType Ty,
SourceLocation Loc,
@@ -9151,6 +9153,7 @@ class BuiltinCandidateTypeSet {
bool hasNonRecordTypes() { return HasNonRecordTypes; }
bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; }
bool hasNullPtrType() const { return HasNullPtrType; }
+ bool hasReflectionType() const { return HasReflectionType; }
};
} // end anonymous namespace
@@ -9332,6 +9335,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
MatrixTypes.insert(Ty);
} else if (Ty->isNullPtrType()) {
HasNullPtrType = true;
+ } else if (Ty->isMetaInfoType()) {
+ HasReflectionType = true;
} else if (AllowUserConversions && TyIsRec) {
// No conversion functions in incomplete types.
if (!SemaRef.isCompleteType(Loc, Ty))
@@ -9811,6 +9816,14 @@ class BuiltinOperatorOverloadBuilder {
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
+
+ if (CandidateTypes[ArgIdx].hasReflectionType()) {
+ CanQualType InfoTy = S.Context.getCanonicalType(S.Context.MetaInfoTy);
+ if (AddedTypes.insert(InfoTy).second) {
+ QualType ParamTypes[2] = {InfoTy, InfoTy};
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
+ }
+ }
}
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 0d1e01df75d94..d9a8b2fea89fe 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -8111,6 +8111,18 @@ static Expr *BuildExpressionFromIntegralTemplateArgumentValue(
return E;
}
+/// Construct a new reflect expression that refers to the given
+/// entity with the given source-location of the reflection operator.
+static ExprResult BuildExpressionFromReflection(Sema &S, const APValue &RV,
+ SourceLocation CaretCaretLoc) {
+ // TODO(Reflection): Add support for NamespaceReference, TemplateReference,
+ // and DeclRefExpr.
+ return CXXReflectExpr::Create(
+ S.Context, CaretCaretLoc,
+ static_cast<TypeSourceInfo *>(
+ const_cast<void *>(RV.getReflectionOpaqueOperand())));
+}
+
static Expr *BuildExpressionFromNonTypeTemplateArgumentValue(
Sema &S, QualType T, const APValue &Val, SourceLocation Loc) {
auto MakeInitList = [&](ArrayRef<Expr *> Elts) -> Expr * {
@@ -8176,7 +8188,7 @@ static Expr *BuildExpressionFromNonTypeTemplateArgumentValue(
case APValue::Indeterminate:
llvm_unreachable("Unexpected APValue kind.");
case APValue::LValue:
- case APValue::MemberPointer:
+ case APValue::MemberPointer: {
// There isn't necessarily a valid equivalent source-level syntax for
// these; in particular, a naive lowering might violate access control.
// So for now we lower to a ConstantExpr holding the value, wrapped around
@@ -8190,6 +8202,9 @@ static Expr *BuildExpressionFromNonTypeTemplateArgumentValue(
auto *OVE = new (S.Context) OpaqueValueExpr(Loc, T, VK);
return ConstantExpr::Create(S.Context, OVE, Val);
}
+ case APValue::Reflection:
+ return BuildExpressionFromReflection(S, Val, Loc).get();
+ }
llvm_unreachable("Unhandled APValue::ValueKind enum");
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index cc126f9000717..a32fccfc55ff4 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13395,7 +13395,19 @@ StmtResult TreeTransform<Derived>::TransformUnresolvedSYCLKernelCallStmt(
template <typename Derived>
ExprResult TreeTransform<Derived>::TransformCXXReflectExpr(CXXReflectExpr *E) {
// TODO(reflection): Implement its transform
- assert(false && "not implemented yet");
+
+ switch (E->getKind()) {
+ case ReflectionKind::Type: {
+ TypeSourceInfo *NewT = getDerived().TransformType(E->getTypeSourceInfo());
+ if (!NewT)
+ return ExprError();
+ return SemaRef.BuildCXXReflectExpr(E->getOperatorLoc(), NewT);
+ }
+ case ReflectionKind::Null:
+ llvm_unreachable("A null reflection should not reach here");
+ }
+
+ assert(false && "unknown or unimplemented reflection entities");
return ExprError();
}
diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp
index 74265d5fce908..0dae1d6a35c8b 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -286,6 +286,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::BFloat16:
ID = PREDEF_TYPE_BFLOAT16_ID;
break;
+ case BuiltinType::MetaInfo:
+ ID = PREDEF_TYPE_META_INFO_ID;
+ break;
}
return TypeIdx(0, ID);
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index a018a378e9f44..9e690dadd25b9 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -8058,6 +8058,9 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_NULLPTR_ID:
T = Context.NullPtrTy;
break;
+ case PREDEF_TYPE_META_INFO_ID:
+ T = Context.MetaInfoTy;
+ break;
case PREDEF_TYPE_CHAR8_ID:
T = Context.Char8Ty;
break;
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 87cec16a76323..4ded925d08a38 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -540,8 +540,19 @@ void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
}
void ASTStmtReader::VisitCXXReflectExpr(CXXReflectExpr *E) {
- // TODO(Reflection): Implement this.
- assert(false && "not implemented yet");
+ // TODO(Reflection): add support for TemplateReference, NamespaceReference and
+ // DeclRefExpr
+ VisitExpr(E);
+ E->CaretCaretLoc = readSourceLocation();
+ E->Kind = static_cast<ReflectionKind>(Record.readInt());
+ switch (E->Kind) {
+ case ReflectionKind::Null:
+ E->Operand = nullptr;
+ break;
+ case ReflectionKind::Type:
+ E->Operand = Record.readTypeSourceInfo();
+ break;
+ }
}
void ASTStmtReader::VisitSYCLKernelCallStmt(SYCLKernelCallStmt *S) {
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 70477f4cf4001..476ffe8726c66 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -475,8 +475,19 @@ void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *E) {
}
void ASTStmtWriter::VisitCXXReflectExpr(CXXReflectExpr *E) {
- // TODO(Reflection): Implement this.
- assert(false && "not implemented yet");
+ // TODO(Reflection): add support for TemplateReference, NamespaceReference and
+ // DeclRefExpr
+ VisitExpr(E);
+ Record.AddSourceLocation(E->getOperatorLoc());
+ Record.push_back(static_cast<uint64_t>(E->getKind()));
+ switch (E->getKind()) {
+ case ReflectionKind::Null:
+ break;
+ case ReflectionKind::Type:
+ Record.AddTypeSourceInfo(E->getTypeSourceInfo());
+ break;
+ }
+ Code = serialization::EXPR_REFLECT;
}
void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) {
diff --git a/clang/lib/UnifiedSymbolResolution/USRGeneration.cpp b/clang/lib/UnifiedSymbolResolution/USRGeneration.cpp
index 5f689ad32159b..99901e9601ac0 100644
--- a/clang/lib/UnifiedSymbolResolution/USRGeneration.cpp
+++ b/clang/lib/UnifiedSymbolResolution/USRGeneration.cpp
@@ -805,6 +805,9 @@ void USRGenerator::VisitType(QualType T) {
case BuiltinType::NullPtr:
Out << 'n';
break;
+ case BuiltinType::MetaInfo:
+ Out << "@BT at MetaInfo";
+ break;
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id: \
Out << "@BT@" << #Suffix << "_" << #ImgType; \
diff --git a/clang/test/AST/ast-dump-APValue-reflection.cpp b/clang/test/AST/ast-dump-APValue-reflection.cpp
new file mode 100644
index 0000000000000..750cdf94da7dc
--- /dev/null
+++ b/clang/test/AST/ast-dump-APValue-reflection.cpp
@@ -0,0 +1,14 @@
+// Test without serialization:
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++26 -freflection \
+// RUN: -ast-dump %s -ast-dump-filter Test \
+// RUN: | FileCheck --strict-whitespace %s
+
+void TestReflection() {
+ constexpr auto x = ^^int;
+ // CHECK: | `-VarDecl {{.*}} x 'const std::meta::info' constexpr cinit
+ // CHECK-NEXT: | |-value: Reflection ^^int
+
+ constexpr decltype(^^int) y{};
+ // CHECK: `-VarDecl {{.*}} y {{.*}} constexpr listinit
+ // CHECK-NEXT: |-value: Reflection std::meta::info{}
+}
diff --git a/clang/test/CodeGenCXX/reflection-emit-meta-info-itanium.cpp b/clang/test/CodeGenCXX/reflection-emit-meta-info-itanium.cpp
new file mode 100644
index 0000000000000..a6266165e77f8
--- /dev/null
+++ b/clang/test/CodeGenCXX/reflection-emit-meta-info-itanium.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++26 -freflection -triple x86_64-unknown-linux-gnu \
+// RUN: -emit-llvm -o - %s -verify
+
+int main() {
+ (void)(^^int); // expected-error {{cannot compile this scalar expression yet}}
+ return 0;
+}
diff --git a/clang/test/CodeGenCXX/reflection-mangle-ms.cpp b/clang/test/CodeGenCXX/reflection-emit-meta-info-ms.cpp
similarity index 100%
rename from clang/test/CodeGenCXX/reflection-mangle-ms.cpp
rename to clang/test/CodeGenCXX/reflection-emit-meta-info-ms.cpp
diff --git a/clang/test/CodeGenCXX/reflection-mangle-itanium.cpp b/clang/test/CodeGenCXX/reflection-mangle-itanium.cpp
index a6266165e77f8..b7c18b721f976 100644
--- a/clang/test/CodeGenCXX/reflection-mangle-itanium.cpp
+++ b/clang/test/CodeGenCXX/reflection-mangle-itanium.cpp
@@ -1,7 +1,45 @@
// RUN: %clang_cc1 -std=c++26 -freflection -triple x86_64-unknown-linux-gnu \
-// RUN: -emit-llvm -o - %s -verify
+// RUN: -emit-llvm -o - %s | FileCheck %s
+
+using info = decltype(^^int);
+
+template <auto A>
+void foo () {}
int main() {
- (void)(^^int); // expected-error {{cannot compile this scalar expression yet}}
+ foo <info {}> ();
+ // CHECK: @_Z3fooITnDaLDmnuEEvv
+ foo <^^void> ();
+ // CHECK: @_Z3fooITnDaLDmtyvEEvv
+ foo <^^bool> ();
+ // CHECK: @_Z3fooITnDaLDmtybEEvv
+ foo <^^char> ();
+ // CHECK: @_Z3fooITnDaLDmtycEEvv
+ foo <^^signed char> ();
+ // CHECK: @_Z3fooITnDaLDmtyaEEvv
+ foo <^^unsigned char> ();
+ // CHECK: @_Z3fooITnDaLDmtyhEEvv
+ foo <^^short> ();
+ // CHECK: @_Z3fooITnDaLDmtysEEvv
+ foo <^^unsigned short> ();
+ // CHECK: @_Z3fooITnDaLDmtytEEvv
+ foo <^^int> ();
+ // CHECK: @_Z3fooITnDaLDmtyiEEvv
+ foo <^^unsigned int> ();
+ // CHECK: @_Z3fooITnDaLDmtyjEEvv
+ foo <^^long> ();
+ // CHECK: @_Z3fooITnDaLDmtylEEvv
+ foo <^^unsigned long> ();
+ // CHECK: @_Z3fooITnDaLDmtymEEvv
+ foo <^^long long> ();
+ // CHECK: @_Z3fooITnDaLDmtyxEEvv
+ foo <^^unsigned long long> ();
+ // CHECK: @_Z3fooITnDaLDmtyyEEvv
+ foo <^^float> ();
+ // CHECK: @_Z3fooITnDaLDmtyfEEvv
+ foo <^^double> ();
+ // CHECK: @_Z3fooITnDaLDmtydEEvv
+ foo <^^long double> ();
+ // CHECK: @_Z3fooITnDaLDmtyeEEvv
return 0;
}
diff --git a/clang/test/PCH/reflection.cpp b/clang/test/PCH/reflection.cpp
new file mode 100644
index 0000000000000..73e98ea68c7ba
--- /dev/null
+++ b/clang/test/PCH/reflection.cpp
@@ -0,0 +1,14 @@
+// Test without PCH
+// RUN: %clang_cc1 -std=c++26 -freflection %s -include %S/reflection_include.h -fsyntax-only -verify
+
+// RUN: %clang_cc1 -std=c++26 -freflection -x c++-header %S/reflection_include.h -emit-pch -o %t
+// RUN: %clang_cc1 -std=c++26 -freflection -include-pch %t -verify %s
+
+// expected-no-diagnostics
+
+
+static_assert(^^int == ^^int);
+static_assert(^^int != ^^double);
+static_assert(info{} != ^^int);
+static_assert(__is_same(decltype(^^int), info));
+static_assert(__is_same(decltype(^^double), info));
diff --git a/clang/test/PCH/reflection_include.h b/clang/test/PCH/reflection_include.h
new file mode 100644
index 0000000000000..782aff5bbd3fe
--- /dev/null
+++ b/clang/test/PCH/reflection_include.h
@@ -0,0 +1 @@
+using info = decltype(^^int);
diff --git a/clang/test/Sema/reflection-meta-info.fail.cpp b/clang/test/Sema/reflection-meta-info.fail.cpp
new file mode 100644
index 0000000000000..e4332990f5e29
--- /dev/null
+++ b/clang/test/Sema/reflection-meta-info.fail.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 %s -std=c++26 -freflection -fsyntax-only -verify
+// RUN: %clang_cc1 %s -std=c++26 -freflection -fexperimental-new-constant-interpreter -fsyntax-only -verify
+
+using info = decltype(^^int);
+
+struct X { int a; }; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'std::meta::info' to 'const X' for 1st argument}} \
+ // expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'std::meta::info' to 'X' for 1st argument}} \
+ // expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
+template <typename T = X, auto ptm = &X::a>
+constexpr auto ptmOp = ((T)(^^int)).*ptm; // expected-error {{no matching conversion for C-style cast from 'std::meta::info' to 'X'}}
+constexpr auto var = ptmOp<>; // expected-note {{in instantiation of variable template specialization 'ptmOp' requested here}}
+
+static_assert(^^int == ^^float); // expected-error {{static assertion failed due to requirement '^^int == ^^float'}}
+static_assert(info{} == ^^int); // expected-error {{static assertion failed due to requirement 'std::meta::info{} == ^^int'}}
+
+consteval void test()
+{
+ (^^char)++; // expected-error {{cannot increment value of type 'std::meta::info'}}
+ (^^short)++; // expected-error {{cannot increment value of type 'std::meta::info'}}
+ (^^int)++; // expected-error {{cannot increment value of type 'std::meta::info'}}
+ (^^char)--; // expected-error {{cannot decrement value of type 'std::meta::info'}}
+ (^^short)--; // expected-error {{cannot decrement value of type 'std::meta::info'}}
+ (^^int)--; // expected-error {{cannot decrement value of type 'std::meta::info'}}
+
+ ++(^^char); // expected-error {{cannot increment value of type 'std::meta::info'}}
+ ++(^^short); // expected-error {{cannot increment value of type 'std::meta::info'}}
+ ++(^^int); // expected-error {{cannot increment value of type 'std::meta::info'}}
+ --(^^char); // expected-error {{cannot decrement value of type 'std::meta::info'}}
+ --(^^short); // expected-error {{cannot decrement value of type 'std::meta::info'}}
+ --(^^int); // expected-error {{cannot decrement value of type 'std::meta::info'}}
+
+ ~(^^int); // expected-error {{invalid argument type 'std::meta::info' to unary expression}}
+ !(^^float); // expected-error {{invalid argument type 'std::meta::info' to unary expression}}
+
+ (^^int) + (^^int); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+ (^^double) - (^^float); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+ (^^char) * (^^short); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+ (^^long) / (^^long); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+
+ (^^int) & (^^int); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+ (^^int) | (^^int); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+ (^^int) ^ (^^int); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+
+ (^^int) < (^^int); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+ (^^int) > (^^int); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+ (^^int) <= (^^int); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+ (^^int) >= (^^int); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+ (^^int) <=>(^^int); // expected-error {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+
+ // expected-error at +2 {{value of type 'std::meta::info' is not contextually convertible to 'bool'}}
+ // expected-error at +1 {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+ (^^int) && (^^int);
+ // expected-error at +2 {{value of type 'std::meta::info' is not contextually convertible to 'bool'}}
+ // expected-error at +1 {{invalid operands to binary expression ('std::meta::info' and 'std::meta::info')}}
+ (^^int) || (^^int);
+}
diff --git a/clang/test/Sema/reflection-meta-info.pass.cpp b/clang/test/Sema/reflection-meta-info.pass.cpp
new file mode 100644
index 0000000000000..46b2420af43f6
--- /dev/null
+++ b/clang/test/Sema/reflection-meta-info.pass.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 %s -std=c++26 -freflection -fsyntax-only
+// RUN: %clang_cc1 %s -std=c++26 -freflection -fexperimental-new-constant-interpreter -fsyntax-only
+
+typedef int int32_t;
+using A = int;
+
+using info = decltype(^^int);
+
+template <auto R>
+consteval auto f1() {
+ return R;
+}
+
+template <decltype(^^int) R>
+consteval auto f2() {
+ return R;
+}
+
+consteval void test()
+{
+ constexpr auto r = ^^int;
+ constexpr auto q = ^^float;
+ constexpr info v{};
+
+ static_assert(__is_same(decltype(^^int), info));
+ static_assert(__is_same(decltype(^^float), info));
+ static_assert(__is_same(decltype(^^double), info));
+ static_assert(__is_same(decltype(^^long), info));
+ static_assert(__is_same(decltype(^^long long), info));
+ static_assert(__is_same(decltype(^^short), info));
+ static_assert(__is_same(decltype(^^char), info));
+ static_assert(__is_same(decltype(^^unsigned char), info));
+ static_assert(__is_same(decltype(^^unsigned short), info));
+ static_assert(__is_same(decltype(^^unsigned int), info));
+ static_assert(__is_same(decltype(^^unsigned long), info));
+ static_assert(__is_same(decltype(^^unsigned long long), info));
+ static_assert(__is_same(decltype(^^info), info));
+
+ static_assert(__is_same(decltype(^^int), decltype(^^int)));
+ static_assert(__is_same(decltype(^^int), decltype(^^float)));
+ static_assert(__is_same(decltype(^^int), decltype(^^char)));
+ static_assert(__is_same(decltype(^^double), decltype(^^float)));
+
+ static_assert(!__is_same(decltype(^^int), int));
+ static_assert(__is_scalar(info));
+
+ static_assert(f1< ^^int >() == ^^int);
+ static_assert(f1< ^^A >() != ^^int);
+ static_assert(f1< ^^float>() != ^^int);
+
+ static_assert(f2<r>() == ^^int);
+ static_assert(f2<^^float>() != ^^int);
+
+ static_assert(sizeof(info) == 8);
+ static_assert(alignof(info) == 1);
+ static_assert(sizeof(decltype(^^int)) == sizeof(decltype(^^float)));
+ static_assert(^^int32_t != ^^int);
+ static_assert(^^const int != ^^int);
+ static_assert(^^volatile int32_t == ^^volatile int);
+ static_assert(^^const volatile int32_t == ^^const volatile int);
+ static_assert(^^A != ^^int);
+
+
+ static_assert(^^int == ^^int);
+ static_assert(^^int != ^^float);
+ static_assert(^^float != ^^int);
+ static_assert(!(^^float == ^^int));
+ static_assert(r != q);
+
+ int a;
+ static_assert(^^int == ^^decltype(a));
+
+ using foo = const int;
+ static_assert(^^foo != ^^const int);
+ static_assert(^^const foo == ^^const int);
+ static_assert(^^const int == ^^int const);
+}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 6e30ffd6b322d..bf641c27f8c1c 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -1563,6 +1563,7 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
case BuiltinType::Void:
case BuiltinType::NullPtr:
+ case BuiltinType::MetaInfo:
case BuiltinType::Dependent:
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id:
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 503f5da8af90f..592974804aad5 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -696,6 +696,32 @@ TEST_P(ImportType, ImportUsingType) {
cxxNewExpr(hasType(pointerType(pointee(usingType())))))));
}
+struct ImportReflection : ASTImporterOptionSpecificTestBase {
+ std::vector<std::string> getExtraArgs() const override {
+ return {"-Xclang", "-freflection"};
+ }
+};
+
+TEST_P(ImportReflection, ImportMetaInfoBuiltinType) {
+ Decl *FromTU = getTuDecl("using declToImport = decltype(^^int);", Lang_CXX26,
+ "input.cc");
+ auto *FromTA = FirstDeclMatcher<TypeAliasDecl>().match(
+ FromTU, typeAliasDecl(hasName("declToImport")));
+ ASSERT_TRUE(FromTA);
+
+ const auto *FromBT =
+ FromTA->getUnderlyingType().getCanonicalType()->getAs<BuiltinType>();
+ ASSERT_TRUE(FromBT);
+ ASSERT_EQ(BuiltinType::MetaInfo, FromBT->getKind());
+
+ auto *ToTA = Import(FromTA, Lang_CXX26);
+ ASSERT_TRUE(ToTA);
+ const auto *ToBT =
+ ToTA->getUnderlyingType().getCanonicalType()->getAs<BuiltinType>();
+ ASSERT_TRUE(ToBT);
+ EXPECT_EQ(BuiltinType::MetaInfo, ToBT->getKind());
+}
+
TEST_P(ImportDecl, ImportFunctionTemplateDecl) {
MatchVerifier<Decl> Verifier;
testImport("template <typename T> void declToImport() { };", Lang_CXX03, "",
@@ -10873,6 +10899,9 @@ INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportInjectedClassNameType,
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportMatrixType,
DefaultTestValuesForRunOptions);
+INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportReflection,
+ DefaultTestValuesForRunOptions);
+
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportTemplateParmDeclDefaultValue,
DefaultTestValuesForRunOptions);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 2bfa187c009a7..07d08e181eae0 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -4904,6 +4904,9 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type) {
case clang::BuiltinType::NullPtr:
return lldb::eEncodingUint;
+ case clang::BuiltinType::MetaInfo:
+ return lldb::eEncodingUint;
+
case clang::BuiltinType::Kind::ARCUnbridgedCast:
case clang::BuiltinType::Kind::BoundMember:
case clang::BuiltinType::Kind::BuiltinFn:
>From 48133336caf74cd9dc0617983df1c9e7a7918a53 Mon Sep 17 00:00:00 2001
From: changkhothuychung <nhat7203 at gmail.com>
Date: Thu, 23 Jul 2026 15:44:27 -0400
Subject: [PATCH 2/2] implement std::meta::is_type
---
clang/include/clang/Basic/Builtins.td | 6 ++
clang/lib/AST/ASTContext.cpp | 3 +
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 10 +++
clang/lib/AST/ByteCode/Reflect.h | 2 +
clang/lib/AST/ExprConstant.cpp | 7 ++
clang/lib/Frontend/InitPreprocessor.cpp | 4 ++
clang/test/SemaCXX/builtin-meta-is-type.cpp | 48 +++++++++++++
clang/test/SemaCXX/consteval-builtin.cpp | 18 +++++
clang/utils/TableGen/ClangBuiltinsEmitter.cpp | 1 +
libcxx/docs/FeatureTestMacroTable.rst | 2 +
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/meta | 38 +++++++++++
libcxx/include/module.modulemap.in | 5 ++
libcxx/include/version | 4 ++
.../meta.version.compile.pass.cpp | 68 +++++++++++++++++++
.../version.version.compile.pass.cpp | 33 +++++++++
libcxx/test/std/meta/is_type.compile.pass.cpp | 51 ++++++++++++++
.../generate_feature_test_macro_components.py | 7 ++
18 files changed, 308 insertions(+)
create mode 100644 clang/test/SemaCXX/builtin-meta-is-type.cpp
create mode 100644 libcxx/include/meta
create mode 100644 libcxx/test/std/language.support/support.limits/support.limits.general/meta.version.compile.pass.cpp
create mode 100644 libcxx/test/std/meta/is_type.compile.pass.cpp
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 344a712ddc585..244a791938093 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1207,6 +1207,12 @@ def IsWithinLifetime : LangBuiltin<"CXX_LANG"> {
let Prototype = "bool(void*)";
}
+def MetaIsType : LangBuiltin<"CXX_LANG"> {
+ let Spellings = ["__builtin_meta_is_type"];
+ let Attributes = [NoThrow, Consteval];
+ let Prototype = "bool(std::meta::info)";
+}
+
def ClearPadding : Builtin {
let Spellings = ["__builtin_clear_padding"];
let Attributes = [NoThrow, CustomTypeChecking];
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index c94598662915d..eef973690a350 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -12835,6 +12835,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
case 'M':
Type = Context.getObjCSuperType();
break;
+ case 'r':
+ Type = Context.MetaInfoTy;
+ break;
case 'a':
Type = Context.getBuiltinVaListType();
assert(!Type.isNull() && "builtin va list type not initialized!");
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index a539fb26abc08..de48e2b84fed9 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2535,6 +2535,13 @@ static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC,
return false;
}
+static bool interp__builtin_meta_is_type(InterpState &S, CodePtr OpPC,
+ const CallExpr *) {
+ const Reflect &R = S.Stk.pop<Reflect>();
+ S.Stk.push<Boolean>(Boolean::from(R.getKind() == ReflectionKind::Type));
+ return true;
+}
+
static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
const CallExpr *Call) {
@@ -5454,6 +5461,9 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case Builtin::BI__builtin_is_within_lifetime:
return interp__builtin_is_within_lifetime(S, OpPC, Call);
+ case Builtin::BI__builtin_meta_is_type:
+ return interp__builtin_meta_is_type(S, OpPC, Call);
+
case Builtin::BI__builtin_elementwise_add_sat:
return interp__builtin_elementwise_int_binop(
S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) {
diff --git a/clang/lib/AST/ByteCode/Reflect.h b/clang/lib/AST/ByteCode/Reflect.h
index dcd00a3bad782..f5b31743f5f7a 100644
--- a/clang/lib/AST/ByteCode/Reflect.h
+++ b/clang/lib/AST/ByteCode/Reflect.h
@@ -31,6 +31,8 @@ class Reflect final {
Reflect(ReflectionKind Kind, const void *Operand)
: Kind(Kind), Operand(Operand) {}
+ ReflectionKind getKind() const { return Kind; }
+
ComparisonCategoryResult compare(const Reflect &RHS) const {
llvm::FoldingSetNodeID LID, RID;
APValue(Kind, Operand).Profile(LID);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 30086822583d8..90d7771f61885 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -17252,6 +17252,13 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return Success(*result, E);
return false;
+ case Builtin::BI__builtin_meta_is_type: {
+ APValue Reflection;
+ if (!EvaluateReflection(E->getArg(0), Reflection, Info))
+ return false;
+ return Success(Reflection.getReflectionOperandKind() == ReflectionKind::Type, E);
+ }
+
case Builtin::BI__builtin_ctz:
case Builtin::BI__builtin_ctzl:
case Builtin::BI__builtin_ctzll:
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 8b6ff844d0daa..0266734132a73 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -766,6 +766,10 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_variadic_friend", "202403L");
Builder.defineMacro("__cpp_trivial_relocatability", "202502L");
+ // C++26 reflection.
+ if (LangOpts.Reflection)
+ Builder.defineMacro("__cpp_impl_reflection", "202506L");
+
if (LangOpts.Char8)
Builder.defineMacro("__cpp_char8_t", "202207L");
Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");
diff --git a/clang/test/SemaCXX/builtin-meta-is-type.cpp b/clang/test/SemaCXX/builtin-meta-is-type.cpp
new file mode 100644
index 0000000000000..7060a2c06772a
--- /dev/null
+++ b/clang/test/SemaCXX/builtin-meta-is-type.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 %s -std=c++26 -freflection -fsyntax-only -verify
+// RUN: %clang_cc1 %s -std=c++26 -freflection -fexperimental-new-constant-interpreter -fsyntax-only -verify
+
+using info = decltype(^^int);
+
+struct S {};
+namespace A{};
+
+consteval void test_pass() {
+ static_assert(__builtin_meta_is_type(^^int));
+ static_assert(__builtin_meta_is_type(^^unsigned));
+ static_assert(__builtin_meta_is_type(^^long));
+ static_assert(__builtin_meta_is_type(^^long long));
+ static_assert(__builtin_meta_is_type(^^short));
+ static_assert(__builtin_meta_is_type(^^char));
+ static_assert(__builtin_meta_is_type(^^signed char));
+ static_assert(__builtin_meta_is_type(^^unsigned char));
+ static_assert(__builtin_meta_is_type(^^wchar_t));
+ static_assert(__builtin_meta_is_type(^^char8_t));
+ static_assert(__builtin_meta_is_type(^^char16_t));
+ static_assert(__builtin_meta_is_type(^^char32_t));
+ static_assert(__builtin_meta_is_type(^^bool));
+ static_assert(__builtin_meta_is_type(^^float));
+ static_assert(__builtin_meta_is_type(^^double));
+ static_assert(__builtin_meta_is_type(^^long double));
+ static_assert(__builtin_meta_is_type(^^void));
+ static_assert(__builtin_meta_is_type(^^decltype(nullptr)));
+
+ constexpr info null{};
+ static_assert(!__builtin_meta_is_type(null));
+}
+
+consteval void test_fail() {
+ static_assert(__builtin_meta_is_type(^^S)); // expected-error {{unknown or unimplemented reflectable entity}}
+ static_assert(!__builtin_meta_is_type(^^A)); // expected-error {{unknown or unimplemented reflectable entity}}
+}
+
+consteval bool test_with_no_arg() {
+ return __builtin_meta_is_type(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+}
+
+consteval bool test_with_more_than_args_needed() {
+ return __builtin_meta_is_type(^^int, ^^float); // expected-error {{too many arguments to function call, expected 1, have 2}}
+}
+
+consteval bool test_with_wrong_type() {
+ return __builtin_meta_is_type(42); // expected-error {{cannot initialize a parameter of type 'std::meta::info' with an rvalue of type 'int'}}
+}
diff --git a/clang/test/SemaCXX/consteval-builtin.cpp b/clang/test/SemaCXX/consteval-builtin.cpp
index 3ba95b4dbd9b5..7b45e3ddc1f78 100644
--- a/clang/test/SemaCXX/consteval-builtin.cpp
+++ b/clang/test/SemaCXX/consteval-builtin.cpp
@@ -25,6 +25,24 @@
// precxx20-error at -3 {{does not have the constexpr builtin}}
// c-error at -4 {{does not have the constexpr builtin}}
+#if __has_builtin(__builtin_meta_is_type)
+#error has the builtin
+#else
+#error does not have the builtin
+#endif
+// cxx20-cxx26-error at -4 {{has the builtin}}
+// precxx20-error at -3 {{does not have the builtin}}
+// c-error at -4 {{does not have the builtin}}
+
+#if __has_constexpr_builtin(__builtin_meta_is_type)
+#error has the constexpr builtin
+#else
+#error does not have the constexpr builtin
+#endif
+// cxx20-cxx26-error at -4 {{has the constexpr builtin}}
+// precxx20-error at -3 {{does not have the constexpr builtin}}
+// c-error at -4 {{does not have the constexpr builtin}}
+
#if __cplusplus < 201103L
#define static_assert __extension__ _Static_assert
#define CONSTEXPR11
diff --git a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
index 22c81522f9e41..259df9275641a 100644
--- a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
+++ b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
@@ -376,6 +376,7 @@ class PrototypeParser {
.Case("short", "s")
.Case("sigjmp_buf", "SJ")
.Case("size_t", "z")
+ .Case("std::meta::info", "r")
.Case("ucontext_t", "K")
.Case("uint8_t", "UBi")
.Case("uint16_t", "UTi")
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 6bf2f35fb4212..4be0f3a2f10d2 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -522,6 +522,8 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_reference_wrapper`` ``202403L``
---------------------------------------------------------- -----------------
+ ``__cpp_lib_reflection`` ``202506L``
+ ---------------------------------------------------------- -----------------
``__cpp_lib_saturation_arithmetic`` ``202603L``
---------------------------------------------------------- -----------------
``__cpp_lib_senders`` *unimplemented*
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index b40f586161e62..d76a92fda3aa5 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -1060,6 +1060,7 @@ set(files
mdspan
memory
memory_resource
+ meta
mutex
new
numbers
diff --git a/libcxx/include/meta b/libcxx/include/meta
new file mode 100644
index 0000000000000..b0954ea86d82f
--- /dev/null
+++ b/libcxx/include/meta
@@ -0,0 +1,38 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_META
+#define _LIBCPP_META
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26 && defined(__cpp_impl_reflection)
+
+namespace meta {
+
+using info = decltype(^^int);
+
+# if __has_builtin(__builtin_meta_is_type)
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI consteval bool is_type(info __r) {
+ return __builtin_meta_is_type(__r);
+}
+# endif
+
+} // namespace meta
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_META
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 39b4e0bb986c6..947e754271798 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1739,6 +1739,11 @@ module std {
export *
}
+ module meta {
+ header "meta"
+ export *
+ }
+
module mutex {
module lock_guard { header "__mutex/lock_guard.h" }
module mutex { header "__mutex/mutex.h" }
diff --git a/libcxx/include/version b/libcxx/include/version
index 4a6b01093641d..31fafd4878f06 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -230,6 +230,7 @@ __cpp_lib_raw_memory_algorithms 202411L <memory>
__cpp_lib_rcu 202306L <rcu>
__cpp_lib_reference_from_temporary 202202L <type_traits>
__cpp_lib_reference_wrapper 202403L <functional>
+__cpp_lib_reflection 202506L <meta>
__cpp_lib_remove_cvref 201711L <type_traits>
__cpp_lib_result_of_sfinae 201210L <functional> <type_traits>
__cpp_lib_robust_nonmodifying_seq_ops 201304L <algorithm>
@@ -626,6 +627,9 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_raw_memory_algorithms 202411L
// # define __cpp_lib_rcu 202306L
# define __cpp_lib_reference_wrapper 202403L
+# if defined(__cpp_impl_reflection)
+# define __cpp_lib_reflection 202506L
+# endif
# define __cpp_lib_saturation_arithmetic 202603L
// # define __cpp_lib_senders 202406L
// # define __cpp_lib_smart_ptr_owner_equality 202306L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/meta.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/meta.version.compile.pass.cpp
new file mode 100644
index 0000000000000..ffb3107747251
--- /dev/null
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/meta.version.compile.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING: This test was generated by generate_feature_test_macro_components.py
+// and should not be edited manually.
+
+// <meta>
+
+// Test the feature test macros defined by <meta>
+
+// clang-format off
+
+#include <meta>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 14
+
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined before c++26"
+# endif
+
+#elif TEST_STD_VER == 14
+
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined before c++26"
+# endif
+
+#elif TEST_STD_VER == 17
+
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined before c++26"
+# endif
+
+#elif TEST_STD_VER == 20
+
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined before c++26"
+# endif
+
+#elif TEST_STD_VER == 23
+
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined before c++26"
+# endif
+
+#elif TEST_STD_VER > 23
+
+# if defined(__cpp_impl_reflection)
+# ifndef __cpp_lib_reflection
+# error "__cpp_lib_reflection should be defined in c++26"
+# endif
+# if __cpp_lib_reflection != 202506L
+# error "__cpp_lib_reflection should have the value 202506L in c++26"
+# endif
+# else
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined when the requirement 'defined(__cpp_impl_reflection)' is not met!"
+# endif
+# endif
+
+#endif // TEST_STD_VER > 23
+
+// clang-format on
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index f2d74cc99d864..e7ecf2eea855c 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -748,6 +748,10 @@
# error "__cpp_lib_reference_wrapper should not be defined before c++26"
# endif
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined before c++26"
+# endif
+
# ifdef __cpp_lib_remove_cvref
# error "__cpp_lib_remove_cvref should not be defined before c++20"
# endif
@@ -1724,6 +1728,10 @@
# error "__cpp_lib_reference_wrapper should not be defined before c++26"
# endif
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined before c++26"
+# endif
+
# ifdef __cpp_lib_remove_cvref
# error "__cpp_lib_remove_cvref should not be defined before c++20"
# endif
@@ -2868,6 +2876,10 @@
# error "__cpp_lib_reference_wrapper should not be defined before c++26"
# endif
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined before c++26"
+# endif
+
# ifdef __cpp_lib_remove_cvref
# error "__cpp_lib_remove_cvref should not be defined before c++20"
# endif
@@ -4276,6 +4288,10 @@
# error "__cpp_lib_reference_wrapper should not be defined before c++26"
# endif
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined before c++26"
+# endif
+
# ifndef __cpp_lib_remove_cvref
# error "__cpp_lib_remove_cvref should be defined in c++20"
# endif
@@ -5924,6 +5940,10 @@
# error "__cpp_lib_reference_wrapper should not be defined before c++26"
# endif
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined before c++26"
+# endif
+
# ifndef __cpp_lib_remove_cvref
# error "__cpp_lib_remove_cvref should be defined in c++23"
# endif
@@ -7896,6 +7916,19 @@
# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
# endif
+# if defined(__cpp_impl_reflection)
+# ifndef __cpp_lib_reflection
+# error "__cpp_lib_reflection should be defined in c++26"
+# endif
+# if __cpp_lib_reflection != 202506L
+# error "__cpp_lib_reflection should have the value 202506L in c++26"
+# endif
+# else
+# ifdef __cpp_lib_reflection
+# error "__cpp_lib_reflection should not be defined when the requirement 'defined(__cpp_impl_reflection)' is not met!"
+# endif
+# endif
+
# ifndef __cpp_lib_remove_cvref
# error "__cpp_lib_remove_cvref should be defined in c++26"
# endif
diff --git a/libcxx/test/std/meta/is_type.compile.pass.cpp b/libcxx/test/std/meta/is_type.compile.pass.cpp
new file mode 100644
index 0000000000000..9cfec64b7d1cc
--- /dev/null
+++ b/libcxx/test/std/meta/is_type.compile.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// ADDITIONAL_COMPILE_FLAGS(clang): -Xclang -freflection
+
+
+// consteval bool is_type(info);
+
+#include <meta>
+
+#include "test_macros.h"
+
+#if defined(__cpp_impl_reflection) && __has_builtin(__builtin_meta_is_type)
+
+ASSERT_SAME_TYPE(decltype(std::meta::is_type(std::meta::info{})), bool);
+
+template <class T>
+concept is_type_callable = requires(T t) { std::meta::is_type(t); };
+
+static_assert(is_type_callable<std::meta::info>);
+static_assert(!is_type_callable<int>);
+static_assert(!is_type_callable<void*>);
+static_assert(!is_type_callable<decltype(nullptr)>);
+
+static_assert(std::meta::is_type(^^int));
+static_assert(std::meta::is_type(^^unsigned));
+static_assert(std::meta::is_type(^^long));
+static_assert(std::meta::is_type(^^long long));
+static_assert(std::meta::is_type(^^short));
+static_assert(std::meta::is_type(^^char));
+static_assert(std::meta::is_type(^^signed char));
+static_assert(std::meta::is_type(^^unsigned char));
+static_assert(std::meta::is_type(^^wchar_t));
+static_assert(std::meta::is_type(^^char8_t));
+static_assert(std::meta::is_type(^^char16_t));
+static_assert(std::meta::is_type(^^char32_t));
+static_assert(std::meta::is_type(^^bool));
+static_assert(std::meta::is_type(^^float));
+static_assert(std::meta::is_type(^^double));
+static_assert(std::meta::is_type(^^long double));
+static_assert(std::meta::is_type(^^void));
+static_assert(std::meta::is_type(^^decltype(nullptr)));
+
+
+#endif
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index f4e16078d5af0..485f51881341c 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1231,6 +1231,13 @@ def add_version_header(tc):
"values": {"c++26": 202403}, # P2944R3: Comparisons for reference_wrapper
"headers": ["functional"],
},
+ {
+ "name": "__cpp_lib_reflection",
+ "values": {"c++26": 202506}, # P2996R13: Reflection for C++26
+ "headers": ["meta"],
+ "test_suite_guard": "defined(__cpp_impl_reflection)",
+ "libcxx_guard": "defined(__cpp_impl_reflection)",
+ },
{
"name": "__cpp_lib_remove_cvref",
"values": {"c++20": 201711},
More information about the cfe-commits
mailing list