diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index d78c7b6363b5d..008115140e607 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -5501,6 +5501,60 @@ class BuiltinBitCastExpr final } }; +/// Represents a C++26 reflect expression [expr.reflect]. The operand of of the +/// expression is either a: +/// - :: (global namespace) +/// - a reflection-name +/// - a type-id +/// - id-expression. +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); + 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 32b2b6bdb989c..ddc4eb1431108 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2883,6 +2883,8 @@ 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 e5e071f43fa75..5c8235bc50b40 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< + "expected reflectable entity">; +} + def warn_max_tokens : Warning< "the number of preprocessor source tokens (%0) exceeds this token limit (%1)">, InGroup, DefaultIgnore; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 8d6b8a14740ce..ef97b0867321c 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -499,6 +499,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; def ConceptSpecializationExpr : StmtNode; def RequiresExpr : StmtNode; +// c++ 26 reflection +def CXXReflectExpr : StmtNode; + // Obj-C Expressions. def ObjCStringLiteral : StmtNode; def ObjCBoxedExpr : StmtNode; 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 0c9584f1b479f..da9fde57a520f 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3689,6 +3689,11 @@ defm application_extension : BoolFOption<"application-extension", PosFlag, NegFlag>; +defm reflection : BoolFOption<"reflection", + LangOpts<"Reflection">, DefaultFalse, + PosFlag, + NegFlag>; defm sized_deallocation : BoolFOption<"sized-deallocation", LangOpts<"SizedDeallocation">, Default, PosFlag, diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 0d2316f73fb62..7877d65e377cc 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,10 @@ class Parser : public CodeCompletionHandler { /// Implementations are in ParseHLSL.cpp ///@{ + //===--------------------------------------------------------------------===// + // Parses the operand of reflection operator + 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 87b96c2d5ad09..1344593fc8c18 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14756,6 +14756,16 @@ 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/Expr.cpp b/clang/lib/AST/Expr.cpp index 340bb4b2ed6a3..91644a4abe2a6 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3730,6 +3730,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case PackIndexingExprClass: case HLSLOutArgExprClass: case OpenACCAsteriskSizeExprClass: + case CXXReflectExprClass: // These never have a side-effect. return false; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index c7f0ff040194d..6c44aa50a3684 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) + : 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.VoidTy, Operand); + E->setOperatorLoc(OperatorLoc); + E->setOperandRange(OperandLoc); + return E; +} + +CXXReflectExpr *CXXReflectExpr::Create(ASTContext &C, + SourceLocation OperatorLoc, + SourceLocation OperandLoc, + Decl *Operand) { + CXXReflectExpr *E = new (C) CXXReflectExpr(C, C.VoidTy, Operand); + + 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 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 00aaaab957591..cd5cfc5091e06 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -19072,6 +19072,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/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 5572e0a7ae59c..edddda9b0bd9a 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4946,6 +4946,12 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, E = cast(E)->getSubExpr(); goto recurse; + case Expr::CXXReflectExprClass: { + // TODO(Reflection): implement this after introducing std::meta::info + // and add info in APValue + break; + } + // FIXME: invent manglings for all these. case Expr::BlockExprClass: case Expr::ChooseExprClass: diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index ff8ca01ec5477..f4b92df8f86cb 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2566,6 +2566,11 @@ void StmtPrinter::VisitCXXUnresolvedConstructExpr( OS << ')'; } +void StmtPrinter::VisitCXXReflectExpr(CXXReflectExpr *S) { + // TODO(Reflection): Implement this. + llvm_unreachable("not implemented yet"); +} + void StmtPrinter::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *Node) { if (!Node->isImplicitAccess()) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 05b64ccda0d01..0fe938ebaae34 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2167,6 +2167,11 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) { ID.AddInteger(Hasher.CalculateHash()); } +void StmtProfiler::VisitCXXReflectExpr(const CXXReflectExpr *E) { + // TODO(Reflection): Implement this. + llvm_unreachable("not implemented yet"); +} + void StmtProfiler::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *S) { VisitExpr(S); diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index b282a600c0e56..f212c4195e7de 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 && LangOpts.CPlusPlus26 && 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..520c443840c4f 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 DoubleCaret = ConsumeToken(); + Res = ParseCXXReflectExpression(/*OpLoc=*/DoubleCaret); + } + 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..4775f72957d9e --- /dev/null +++ b/clang/lib/Parse/ParseReflect.cpp @@ -0,0 +1,61 @@ +//===--- ParseReflect.cpp - C++26 Reflection Parsing ---------------------===// +// +// 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 implements parsing for reflection facilities. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/LocInfoType.h" +#include "clang/Basic/DiagnosticParse.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" +using namespace clang; + +ExprResult Parser::ParseCXXReflectExpression(SourceLocation OpLoc) { + // TODO(reflection) : support parsing for more reflect-expressions. + EnterExpressionEvaluationContext Unevaluated( + Actions, Sema::ExpressionEvaluationContext::Unevaluated); + + SourceLocation OperandLoc = Tok.getLocation(); + + { + TentativeParsingAction TPA(*this); + // global namespace :: + if (Tok.is(tok::coloncolon)) { + ConsumeToken(); + 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); + + if (QT.isNull()) + return ExprError(); + + if (!TSI) + TSI = Actions.getASTContext().getTrivialTypeSourceInfo(QT, OperandLoc); + + QualType Canon = QT.getCanonicalType(); + if (Canon->isBuiltinType()) { + // Only supports builtin types for now + 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 a50c27610dc96..ffd596e57d9da 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -17783,6 +17783,27 @@ 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 0c8c1d18d317e..1d2f1a0337ecb 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -12938,6 +12938,12 @@ ExprResult TreeTransform::TransformSYCLUniqueStableNameExpr( E->getLocation(), E->getLParenLocation(), E->getRParenLocation(), NewT); } +template +ExprResult TreeTransform::TransformCXXReflectExpr(CXXReflectExpr *E) { + // TODO(reflection): Implement its transform + llvm_unreachable("not implemeted yet"); +} + template ExprResult TreeTransform::TransformPredefinedExpr(PredefinedExpr *E) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index eef97a8588f0b..66e07e34a6ad6 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -529,6 +529,11 @@ void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) { } } +void ASTStmtReader::VisitCXXReflectExpr(CXXReflectExpr *E) { + // TODO(Reflection): Implement this. + llvm_unreachable("not implemented yet"); +} + void ASTStmtReader::VisitSYCLKernelCallStmt(SYCLKernelCallStmt *S) { VisitStmt(S); S->setOriginalStmt(cast(Record.readSubStmt())); @@ -4524,6 +4529,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case EXPR_HLSL_OUT_ARG: S = HLSLOutArgExpr::CreateEmpty(Context); break; + case EXPR_REFLECT: { + S = CXXReflectExpr::CreateEmpty(Context); + break; + } } // We hit a STMT_STOP, so we're done with this expression. diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index acf345392aa1a..0b6d0f71ef694 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -466,6 +466,11 @@ void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *E) { Code = serialization::EXPR_COYIELD; } +void ASTStmtWriter::VisitCXXReflectExpr(CXXReflectExpr *E) { + // TODO(Reflection): Implement this. + llvm_unreachable("not implemented yet"); +} + void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) { VisitExpr(E); Record.AddSourceLocation(E->getKeywordLoc()); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 4e472b7fc38b0..920eeebb37340 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1720,6 +1720,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, switch (S->getStmtClass()) { // C++, OpenMP and ARC stuff we don't support yet. case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::CXXReflectExprClass: case Stmt::CXXTryStmtClass: case Stmt::CXXTypeidExprClass: case Stmt::CXXUuidofExprClass: diff --git a/clang/test/Reflection/parsing-reflection.cpp b/clang/test/Reflection/parsing-reflection.cpp new file mode 100644 index 0000000000000..3b4655a4f8bc1 --- /dev/null +++ b/clang/test/Reflection/parsing-reflection.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 %s -std=c++26 -freflection -fsyntax-only -verify + +namespace a { +struct T {}; +namespace b { +struct U {}; +int x; +} +} + + +int main() +{ + (void)(^^::); + (void)(^^void); + (void)(^^bool); + (void)(^^char); + (void)(^^signed char); + (void)(^^unsigned char); + (void)(^^short); + (void)(^^unsigned short); + (void)(^^int); + (void)(^^unsigned int); + (void)(^^long); + (void)(^^unsigned long); + (void)(^^long long); + (void)(^^float); + (void)(^^double); + + // Not supported yet. + (void)^^a; // expected-error {{expected reflectable entity}} + (void)^^a::; // expected-error {{expected reflectable entity}} + (void)^^a::b::T; // expected-error {{expected reflectable entity}} + (void)^^a::T::; // expected-error {{expected reflectable entity}} + (void)(^^a::b); // expected-error {{expected reflectable entity}} + (void)^^a::b::; // expected-error {{expected reflectable entity}} + (void)^^a::b::U; // expected-error {{expected reflectable entity}} + (void)^^a::b::x; // expected-error {{expected reflectable entity}} + (void)^^a::b::U::; // expected-error {{expected reflectable entity}} +} diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index 0a43d73063c1f..acee22f44f7f7 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -305,6 +305,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::CXXDefaultArgExprClass: case Stmt::CXXDefaultInitExprClass: case Stmt::CXXFoldExprClass: + case Stmt::CXXReflectExprClass: case Stmt::CXXRewrittenBinaryOperatorClass: case Stmt::CXXStdInitializerListExprClass: case Stmt::CXXScalarValueInitExprClass: