[clang] [clang] reflection operator parsing for global namespace and primitive types (PR #164685)

via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 22 12:01:34 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-modules

Author: Nhat Nguyen  (changkhothuychung)

<details>
<summary>Changes</summary>

First step in adding support for reflection, will add reflection operator parsing for the remaining cases in upcoming subsequent PRs.



---

Patch is 22.24 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/164685.diff


27 Files Affected:

- (modified) clang/include/clang/AST/ExprCXX.h (+50) 
- (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+4) 
- (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+5) 
- (modified) clang/include/clang/Basic/Features.def (+2) 
- (modified) clang/include/clang/Basic/LangOptions.def (+1) 
- (modified) clang/include/clang/Basic/StmtNodes.td (+3) 
- (modified) clang/include/clang/Basic/TokenKinds.def (+1) 
- (modified) clang/include/clang/Driver/Options.td (+6-1) 
- (modified) clang/include/clang/Parse/Parser.h (+6) 
- (modified) clang/include/clang/Sema/Sema.h (+11) 
- (modified) clang/include/clang/Serialization/ASTBitCodes.h (+3) 
- (modified) clang/lib/AST/ExprCXX.cpp (+34) 
- (modified) clang/lib/AST/ExprClassification.cpp (+1) 
- (modified) clang/lib/AST/ExprConstant.cpp (+1) 
- (modified) clang/lib/AST/StmtPrinter.cpp (+6) 
- (modified) clang/lib/AST/StmtProfile.cpp (+5) 
- (modified) clang/lib/Lex/Lexer.cpp (+3) 
- (modified) clang/lib/Parse/CMakeLists.txt (+1) 
- (modified) clang/lib/Parse/ParseExpr.cpp (+10) 
- (added) clang/lib/Parse/ParseReflect.cpp (+54) 
- (modified) clang/lib/Parse/ParseTentative.cpp (+3) 
- (modified) clang/lib/Sema/SemaExceptionSpec.cpp (+1) 
- (modified) clang/lib/Sema/SemaExpr.cpp (+19) 
- (modified) clang/lib/Sema/TreeTransform.h (+6) 
- (modified) clang/lib/Serialization/ASTReaderStmt.cpp (+9) 
- (modified) clang/lib/Serialization/ASTWriterStmt.cpp (+6) 
- (added) clang/test/Reflection/parsing-reflection.pass.cpp (+21) 


``````````diff
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 5f16bac94d5e6..5c8b2209d5364 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -5493,6 +5493,56 @@ class BuiltinBitCastExpr final
   }
 };
 
+/// Represents a C++2c reflect expression (P2996).
+class CXXReflectExpr : public Expr {
+
+  // Source locations.
+  SourceLocation OperatorLoc;
+  SourceRange OperandRange;
+
+  CXXReflectExpr(const ASTContext &C, QualType T, QualType Ty);
+  CXXReflectExpr(const ASTContext &C, QualType T, Decl *Arg, bool IsNamespace);
+  CXXReflectExpr(EmptyShell Empty);
+
+public:
+
+  static CXXReflectExpr *Create(ASTContext &C, SourceLocation OperatorLoc,
+                                SourceLocation ArgLoc, QualType Operand);
+
+  static CXXReflectExpr *Create(ASTContext &C, SourceLocation OperatorLoc,
+                                SourceLocation OperandLoc, Decl *Operand);
+
+  static CXXReflectExpr *CreateEmpty(ASTContext& C);
+
+  SourceLocation getBeginLoc() const LLVM_READONLY { return OperatorLoc; }
+  SourceLocation getEndLoc() const LLVM_READONLY {
+    return OperandRange.getEnd();
+  }
+  SourceRange getSourceRange() const {
+    return SourceRange(getBeginLoc(), getEndLoc());
+  }
+
+  /// Returns location of the '^^'-operator.
+  SourceLocation getOperatorLoc() const { return OperatorLoc; }
+  SourceRange getOperandRange() const { return OperandRange; }
+
+  /// Sets the location of the '^^'-operator.
+  void setOperatorLoc(SourceLocation L) { OperatorLoc = L; }
+  void setOperandRange(SourceRange R) { OperandRange = R; }
+
+  child_range children() {
+    return child_range(child_iterator(), child_iterator());
+  }
+
+  const_child_range children() const {
+    return const_child_range(const_child_iterator(), const_child_iterator());
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXReflectExprClass;
+  }
+};
+
 } // namespace clang
 
 #endif // LLVM_CLANG_AST_EXPRCXX_H
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 7a2881f6124f3..7b8a678ffb861 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2883,6 +2883,10 @@ DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, {
   TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
 })
 
+DEF_TRAVERSE_STMT(CXXReflectExpr, {
+  // TODO
+})
+
 // These expressions all might take explicit template arguments.
 // We traverse those if so.  FIXME: implement these.
 DEF_TRAVERSE_STMT(CXXConstructExpr, {})
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index c724136a7fdaf..ea81a2332cd50 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1848,6 +1848,11 @@ def err_placeholder_expected_auto_or_decltype_auto : Error<
   "expected 'auto' or 'decltype(auto)' after concept name">;
 }
 
+let CategoryName = "Reflection Issue" in {
+def err_cannot_reflect_operand : Error<
+  "cannot reflect the provided operand">;
+}
+
 def warn_max_tokens : Warning<
   "the number of preprocessor source tokens (%0) exceeds this token limit (%1)">,
   InGroup<MaxTokens>, DefaultIgnore;
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 0e91b42a132c1..c9d24430326ff 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -380,6 +380,8 @@ FEATURE(cxx_abi_relative_vtable, LangOpts.CPlusPlus && LangOpts.RelativeCXXABIVT
 
 FEATURE(clang_atomic_attributes, true)
 
+FEATURE(reflection, LangOpts.Reflection)
+
 // CUDA/HIP Features
 FEATURE(cuda_noinline_keyword, LangOpts.CUDA)
 EXTENSION(cuda_implicit_host_device_templates, LangOpts.CUDA && LangOpts.OffloadImplicitHostDeviceTemplates)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 84f5ab3443a59..b2051fb536432 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -498,6 +498,7 @@ LANGOPT(BoundsSafety, 1, 0, NotCompatible, "Bounds safety extension for C")
 LANGOPT(EnableLifetimeSafety, 1, 0, NotCompatible, "Experimental lifetime safety analysis for C++")
 
 LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")
+LANGOPT(Reflection      , 1, 0, NotCompatible, "C++26 Reflection")
 
 #undef LANGOPT
 #undef ENUM_LANGOPT
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index bf3686bb372d5..987e1d1408e06 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -177,6 +177,9 @@ def CoyieldExpr : StmtNode<CoroutineSuspendExpr>;
 def ConceptSpecializationExpr : StmtNode<Expr>;
 def RequiresExpr : StmtNode<Expr>;
 
+// c++ 26 reflection
+def CXXReflectExpr : StmtNode<Expr>;
+
 // Obj-C Expressions.
 def ObjCStringLiteral : StmtNode<Expr>;
 def ObjCBoxedExpr : StmtNode<Expr>;
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 564d6010181cc..b7fef8b2de739 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -233,6 +233,7 @@ PUNCTUATOR(greatergreater,      ">>")
 PUNCTUATOR(greaterequal,        ">=")
 PUNCTUATOR(greatergreaterequal, ">>=")
 PUNCTUATOR(caret,               "^")
+PUNCTUATOR(caretcaret,          "^^")
 PUNCTUATOR(caretequal,          "^=")
 PUNCTUATOR(pipe,                "|")
 PUNCTUATOR(pipepipe,            "||")
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 6245cf33a0719..1880459fab52f 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3663,6 +3663,11 @@ defm application_extension : BoolFOption<"application-extension",
   PosFlag<SetTrue, [], [ClangOption, CC1Option],
           "Restrict code to those available for App Extensions">,
   NegFlag<SetFalse>>;
+defm reflection : BoolFOption<"reflection",
+  LangOpts<"Reflection">, DefaultFalse,
+  PosFlag<SetTrue, [], [ClangOption, CC1Option],
+          "Enable C++26 reflection">,
+  NegFlag<SetFalse>>;
 defm sized_deallocation : BoolFOption<"sized-deallocation",
   LangOpts<"SizedDeallocation">, Default<cpp14.KeyPath>,
   PosFlag<SetTrue, [], [], "Enable C++14 sized global deallocation functions">,
@@ -7153,7 +7158,7 @@ defm android_pad_segment : BooleanFFlag<"android-pad-segment">, Group<f_Group>;
 def shared_libflangrt : Flag<["-"], "shared-libflangrt">,
   HelpText<"Link the flang-rt shared library">, Group<Link_Group>,
   Visibility<[FlangOption]>, Flags<[NoArgumentUnused]>;
-def static_libflangrt : Flag<["-"], "static-libflangrt">, 
+def static_libflangrt : Flag<["-"], "static-libflangrt">,
   HelpText<"Link the flang-rt static library">, Group<Link_Group>,
   Visibility<[FlangOption]>, Flags<[NoArgumentUnused]>;
 
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index e301cf1080977..9b8d8f7633f4d 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -150,6 +150,7 @@ enum class TentativeCXXTypeIdContext {
   AsTemplateArgument,
   InTrailingReturnType,
   AsGenericSelectionArgument,
+  AsReflectionOperand
 };
 
 /// The kind of attribute specifier we have found.
@@ -5167,6 +5168,11 @@ class Parser : public CodeCompletionHandler {
   /// Implementations are in ParseHLSL.cpp
   ///@{
 
+
+    //===--------------------------------------------------------------------===//
+    // C++2c: Reflection [P2996]
+    ExprResult ParseCXXReflectExpression(SourceLocation OpLoc);
+
 private:
   bool MaybeParseHLSLAnnotations(Declarator &D,
                                  SourceLocation *EndLoc = nullptr,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f53aafdeb4f36..d07c1160023b3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -14663,6 +14663,17 @@ class Sema final : public SemaBase {
   /// Implementations are in SemaConcept.cpp
   ///@{
 
+public:
+
+    ExprResult ActOnCXXReflectExpr(SourceLocation OpLoc, TypeSourceInfo* T);
+    ExprResult ActOnCXXReflectExpr(SourceLocation OpLoc,
+                                 SourceLocation ArgLoc, Decl *D);
+
+    ExprResult BuildCXXReflectExpr(SourceLocation OperatorLoc,
+                                 SourceLocation OperandLoc, QualType T);
+    ExprResult BuildCXXReflectExpr(SourceLocation OperatorLoc,
+                                  SourceLocation OperandLoc, Decl *D);
+
 public:
   void PushSatisfactionStackEntry(const NamedDecl *D,
                                   const llvm::FoldingSetNodeID &ID) {
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 5d09d5536e5ab..b950c444d9aa2 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1925,6 +1925,9 @@ enum StmtCode {
   EXPR_CONCEPT_SPECIALIZATION,            // ConceptSpecializationExpr
   EXPR_REQUIRES,                          // RequiresExpr
 
+  // Reflection
+  EXPR_REFLECT,
+
   // CUDA
   EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
 
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 95de6a82a5270..b4758465f669a 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1939,6 +1939,40 @@ TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C,
   return new (Mem) TypeTraitExpr(EmptyShell(), IsStoredAsBool);
 }
 
+CXXReflectExpr::CXXReflectExpr(const ASTContext &C, QualType T, QualType Ty)
+: Expr(CXXReflectExprClass, T, VK_PRValue, OK_Ordinary) {}
+
+CXXReflectExpr::CXXReflectExpr(const ASTContext &C, QualType T, Decl *Arg, bool IsNamespace)
+: Expr(CXXReflectExprClass, T, VK_PRValue, OK_Ordinary) {}
+
+CXXReflectExpr::CXXReflectExpr(EmptyShell Empty)
+: Expr(CXXReflectExprClass, Empty) {}
+
+CXXReflectExpr *CXXReflectExpr::Create(ASTContext &C, SourceLocation OperatorLoc,
+                                SourceLocation OperandLoc, QualType Operand) {
+  CXXReflectExpr *E = new (C) CXXReflectExpr(C, C.DependentTy, Operand);
+  E->setOperatorLoc(OperatorLoc);
+  E->setOperandRange(OperandLoc);
+  return E;
+}
+
+CXXReflectExpr *CXXReflectExpr::Create(ASTContext &C,
+                                       SourceLocation OperatorLoc,
+                                       SourceLocation OperandLoc,
+                                       Decl *Operand) {
+  bool IsNamespace = isa<TranslationUnitDecl>(Operand);
+
+  CXXReflectExpr *E = new (C) CXXReflectExpr(C, C.DependentTy, Operand,
+                                             IsNamespace);
+  E->setOperatorLoc(OperatorLoc);
+  E->setOperandRange(OperandLoc);
+  return E;
+}
+
+CXXReflectExpr *CXXReflectExpr::CreateEmpty(ASTContext &C) {
+  return new (C) CXXReflectExpr(EmptyShell());
+}
+
 CUDAKernelCallExpr::CUDAKernelCallExpr(Expr *Fn, CallExpr *Config,
                                        ArrayRef<Expr *> Args, QualType Ty,
                                        ExprValueKind VK, SourceLocation RP,
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index aeacd0dc765ef..4c53c316e989a 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -216,6 +216,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
   case Expr::SourceLocExprClass:
   case Expr::ConceptSpecializationExprClass:
   case Expr::RequiresExprClass:
+  case Expr::CXXReflectExprClass:
     return Cl::CL_PRValue;
 
   case Expr::EmbedExprClass:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index b706b14945b6d..0f14aa3c7258f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -18295,6 +18295,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
   case Expr::ArrayTypeTraitExprClass:
   case Expr::ExpressionTraitExprClass:
   case Expr::CXXNoexceptExprClass:
+  case Expr::CXXReflectExprClass:
     return NoDiag();
   case Expr::CallExprClass:
   case Expr::CXXOperatorCallExprClass: {
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 586c3000f105c..8e5bab721e8e4 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2566,6 +2566,12 @@ void StmtPrinter::VisitCXXUnresolvedConstructExpr(
     OS << ')';
 }
 
+
+void StmtPrinter::VisitCXXReflectExpr(CXXReflectExpr *S) {
+  // TODO: Make this better.
+  OS << "^(...)";
+}
+
 void StmtPrinter::VisitCXXDependentScopeMemberExpr(
                                          CXXDependentScopeMemberExpr *Node) {
   if (!Node->isImplicitAccess()) {
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 589a156a2b6ea..ad37b5e71472e 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2164,6 +2164,11 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
   ID.AddInteger(Hasher.CalculateHash());
 }
 
+void StmtProfiler::VisitCXXReflectExpr(const CXXReflectExpr *E) {
+  VisitExpr(E);
+  // TODO: 
+}
+
 void
 StmtProfiler::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *S) {
   VisitExpr(S);
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index b282a600c0e56..5df36d041d0c1 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -4348,6 +4348,9 @@ bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
     if (Char == '=') {
       CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
       Kind = tok::caretequal;
+    } else if (LangOpts.Reflection && Char == '^') {
+      CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+      Kind = tok::caretcaret;
     } else {
       if (LangOpts.OpenCL && Char == '^')
         Diag(CurPtr, diag::err_opencl_logical_exclusive_or);
diff --git a/clang/lib/Parse/CMakeLists.txt b/clang/lib/Parse/CMakeLists.txt
index e6cbf3b868b7d..8dd120f529b13 100644
--- a/clang/lib/Parse/CMakeLists.txt
+++ b/clang/lib/Parse/CMakeLists.txt
@@ -26,6 +26,7 @@ add_clang_library(clangParse
   ParseTentative.cpp
   Parser.cpp
   ParseOpenACC.cpp
+  ParseReflect.cpp
 
   LINK_LIBS
   clangAST
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 3515343202de1..22963d985b01b 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1208,6 +1208,13 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand,
     AllowSuffix = false;
     Res = ParseUnaryExprOrTypeTraitExpression();
     break;
+  case tok::caretcaret: {
+    if (getLangOpts().Reflection) {
+      SourceLocation FirstCaret = ConsumeToken(); // eat first '^'
+      Res = ParseCXXReflectExpression(/*OpLoc=*/FirstCaret);
+    }
+    break;
+  }
   case tok::ampamp: {      // unary-expression: '&&' identifier
     if (NotPrimaryExpression)
       *NotPrimaryExpression = true;
@@ -2249,6 +2256,9 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
   else if (getLangOpts().C2y && OpTok.is(tok::kw__Countof))
     Diag(OpTok, diag::warn_c2y_compat_keyword) << OpTok.getName();
 
+  if (OpTok.is(tok::caretcaret))
+    return ParseCXXReflectExpression(OpTok.getLocation());
+
   EnterExpressionEvaluationContext Unevaluated(
       Actions, Sema::ExpressionEvaluationContext::Unevaluated,
       Sema::ReuseLambdaContextDecl);
diff --git a/clang/lib/Parse/ParseReflect.cpp b/clang/lib/Parse/ParseReflect.cpp
new file mode 100644
index 0000000000000..817c885ab2804
--- /dev/null
+++ b/clang/lib/Parse/ParseReflect.cpp
@@ -0,0 +1,54 @@
+
+
+
+
+#include "clang/AST/LocInfoType.h"
+#include "clang/Basic/DiagnosticParse.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
+#include "clang/Sema/EnterExpressionEvaluationContext.h"
+using namespace clang;
+
+ExprResult Parser::ParseCXXReflectExpression(SourceLocation OpLoc) {
+  assert(Tok.is(tok::caretcaret) && "expected '^^'");
+  EnterExpressionEvaluationContext Unevaluated(
+      Actions, Sema::ExpressionEvaluationContext::Unevaluated);
+
+  SourceLocation OperandLoc = Tok.getLocation();
+
+  // Parse a leading nested-name-specifier
+  CXXScopeSpec SS;
+  if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
+                                     /*ObjectHasErrors=*/false,
+                                     /*EnteringContext=*/false)) {
+    SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
+    return ExprError();
+  }
+
+  {
+    TentativeParsingAction TPA(*this);
+
+    if (SS.isValid() &&
+               SS.getScopeRep().getKind() == NestedNameSpecifier::Kind::Global) {
+      // Check for global namespace '^^::'
+      TPA.Commit();
+      Decl *TUDecl = Actions.getASTContext().getTranslationUnitDecl();
+      return Actions.ActOnCXXReflectExpr(OpLoc, SourceLocation(), TUDecl);
+    }
+    TPA.Revert();
+  }
+
+  if (isCXXTypeId(TentativeCXXTypeIdContext::AsReflectionOperand)) {
+    TypeResult TR = ParseTypeName(/*TypeOf=*/nullptr);
+    if (TR.isInvalid())
+      return ExprError();
+
+    TypeSourceInfo *TSI = nullptr;
+    QualType QT = Actions.GetTypeFromParser(TR.get(), &TSI);
+
+    return Actions.ActOnCXXReflectExpr(OpLoc, TSI);
+  }
+
+  Diag(OperandLoc, diag::err_cannot_reflect_operand);
+  return ExprError();
+}
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 82f2294ff5bb7..8a3ae2232767e 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -574,6 +574,9 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
     } else if (Context == TentativeCXXTypeIdContext::InTrailingReturnType) {
       TPR = TPResult::True;
       isAmbiguous = true;
+    } else if (Context == TentativeCXXTypeIdContext::AsReflectionOperand) {
+      TPR = TPResult::True;
+      isAmbiguous = true;
     } else
       TPR = TPResult::False;
   }
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index a0483c3027199..ff8d2139289a3 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1379,6 +1379,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
   case Expr::CXXNoexceptExprClass:
   case Expr::CXXNullPtrLiteralExprClass:
   case Expr::CXXPseudoDestructorExprClass:
+  case Expr::CXXReflectExprClass:
   case Expr::CXXScalarValueInitExprClass:
   case Expr::CXXThisExprClass:
   case Expr::CXXUuidofExprClass:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 06b2529011c74..95bc91ab29f90 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -17760,6 +17760,25 @@ void Sema::PushExpressionEvaluationContextForFunction(
   }
 }
 
+ExprResult Sema::ActOnCXXReflectExpr(SourceLocation OpLoc, TypeSourceInfo* TSI) {
+  return BuildCXXReflectExpr(OpLoc, TSI->getTypeLoc().getBeginLoc(), TSI->getType());
+}
+
+ExprResult Sema::ActOnCXXReflectExpr(SourceLocation OpLoc,
+                                     SourceLocation ArgLoc, Decl *D) {
+  return BuildCXXReflectExpr(OpLoc, ArgLoc, D);
+}
+
+ExprResult Sema::BuildCXXReflectExpr(SourceLocation OperatorLoc,
+                                     SourceLocation OperandLoc, QualType T) {
+  return CXXReflectExpr::Create(Context, OperatorLoc, OperandLoc, T);
+}
+
+ExprResult Sema::BuildCXXReflectExpr(SourceLocation OperatorLoc,
+                                     SourceLocation OperandLoc, Decl *D) {
+  return CXXReflectExpr::Create(Context, OperatorLoc, OperandLoc, D);
+}
+
 namespace {
 
 const DeclRefExpr *CheckPossibleDeref(Sema &S, const Expr *PossibleDeref) {
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 6967301483361..6620c422331e4 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -12873,6 +12873,12 @@ ExprResult TreeTransform<Derived>::TransformSYCLUniqueStableNameExpr(
       E->getLocation(), E->getLParenLocation(), E->getRParenLocation(), NewT);
 }
 
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformCXXReflectExpr(CXXReflectExpr *E) {
+  // No subexpressions to recurse over in PR1.
+  return E;
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExp...
[truncated]

``````````

</details>


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


More information about the cfe-commits mailing list