-
Couldn't load subscription status.
- Fork 15k
[clang]: reflection operator parsing for global namespace and primitive types #164692
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
implement views::concat (P2542)
Revert "implement views::concat (P2542) "
| @llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-modules Author: Nhat Nguyen (changkhothuychung) ChangesPatch is 23.30 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/164692.diff 28 Files Affected:
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/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 2173aed5b45af..18bd38c66b5e9 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4945,6 +4945,12 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, E = cast<ConstantExpr>(E)->getSubExpr(); goto recurse; + case Expr::CXXReflectExprClass: { + // TODO: 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 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..8c974d949d87f --- /dev/null +++ b/clang/lib/Parse/ParseReflect.cpp @@ -0,0 +1,61 @@ +//===--- ParseReflect.cpp - C++2c 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) { + 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, + ... [truncated] |
| ✅ With the latest revision this PR passed the C/C++ code formatter. |
Typically we count on the 'experimental' word in the flag to warn that. Do we otherwise diagnose in serialization? I'd rather us not try to do something new there. |
I just want to offer more info for users so that they can understand the status better and not confusing. This is a suggestion not a requirement. |
That’s a good idea, it’d be similar to the C++98 compatibility warning we have that suggests rewriting |
Co-authored-by: Hubert Tong <hubert.reinterpretcast@gmail.com>
| | ||
| // Not supported yet. | ||
| (void)^^a; // expected-error {{expected reflectable entity}} | ||
| (void)^^a::; // expected-error {{expected reflectable entity}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There might be room for a better diagnostic for this case, but I personally think it's fine for now, and we can always work on improving it later.
@erichkeane @cor3ntin Wdyt?
| I left a few more comments, but now I'm out of feedback. Looking forward to seeing this land once maintainers are happy with it!! 🚀 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think we should be able to merge this soon.
clang/lib/Parse/ParseExpr.cpp Outdated
| if (OpTok.is(tok::caretcaret)) | ||
| return ParseCXXReflectExpression(OpTok.getLocation()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t think we need to involve ParseUnaryExprOrTypeTraitExpr() in this (this function is primarily for expressions of the form <something> ( <expr> )); is there any reason we can’t just call ParseCXXReflectExpression() in ParseCastExpression()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On that note, I think it would simplify things if we also moved consuming the ^^ token into ParseCXXReflectExpression() and put an assertion there instead; that’s usually how we do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure I moved it into ParseUnaryExprOrTypeTraitExpr in my fork just because a reflect-expression is formally a unary-expression. Functionally, I don't know of any reason it wouldn't work okay in ParseCastExpression (and I'm pretty sure I had it there at some point). Depends how much we care to mirror the grammar into this call structure, I suppose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure I moved it into
ParseUnaryExprOrTypeTraitExprin my fork just because a reflect-expression is formally a unary-expression. Functionally, I don't know of any reason it wouldn't work okay inParseCastExpression(and I'm pretty sure I had it there at some point).
Ah no, that function is really just for things that are of the form <something> ( <expr> ) like alignof (it just so happens that some of those are unary-expressions); you’ll notice that e.g. prefix ++ or -- are handled directly in ParseCastExpression().
Depends how much we care to mirror the grammar into this call structure, I suppose.
We do care about that in the AST representation usually, but not in the parser itself (e.g. binary expressions are also not parsed recursively because ~15 levels of recursion to parse a single integer literal would be rather sad).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me!
| | ||
| int main() | ||
| { | ||
| (void)(A{}^^(int y){ return y + 1; }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also add
1^^(){ return 1; }(); 1^^{ return 1; }();There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another thing I just noticed; I don’t think we need a separate clang/testReflection directory for this; just put it in clang/test/Parser/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(That also applies to the other test file)
Co-authored-by: Sirraide <aeternalmail@gmail.com>
Co-authored-by: Sirraide <aeternalmail@gmail.com>
Co-authored-by: Sirraide <aeternalmail@gmail.com>
Co-authored-by: Sirraide <aeternalmail@gmail.com>
Co-authored-by: Sirraide <aeternalmail@gmail.com>
This PR implements parsing the reflection operator (^^) for global namespace and primitive types. The goal is to keep the first PR simple. In subsequent PRs, parsing for the remaining requirements will be introduced.
This implementation is based on the fork of @katzdm.
Class
CXXReflectExpris introduced to represent the operand of the reflection operator. For now, in this PR, the type std::meta::info is not implemented yet, so when we construct an AST node CXXReflectExpr,VoidTyis used as placeholder type for now.The file
ParseReflect.cppis introduced, which for now only has the functionParseCXXReflectExpression. It parses the operand of the reflection operator.