diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h index 21647ffa5ac5a4..892a7f165a5fc7 100644 --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -32,6 +32,7 @@ template class BasicReaderBase; class AddrLabelExpr; class ASTContext; + class AttributeCommonInfo; class CharUnits; class CXX26AnnotationAttr; class CXXRecordDecl; @@ -489,6 +490,10 @@ class APValue { return isReflection() && getReflectionKind() == ReflectionKind::Annotation; } + bool isReflectedAttribute() const { + return isReflection() && getReflectionKind() == ReflectionKind::Attribute; + } + void dump() const; void dump(raw_ostream &OS, const ASTContext &Context) const; @@ -678,6 +683,7 @@ class APValue { CXXBaseSpecifier *getReflectedBaseSpecifier() const; TagDataMemberSpec *getReflectedDataMemberSpec() const; CXX26AnnotationAttr *getReflectedAnnotation() const; + AttributeCommonInfo *getReflectedAttribute() const; void setInt(APSInt I) { assert(isInt() && "Invalid accessor"); diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index ea12345ea49f55..134c7e49081b3f 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -5321,7 +5321,8 @@ class BuiltinBitCastExpr final }; /// Represents a C++2c reflect expression (P2996). The operand of the expression -/// is either a type, an expression, a template-name, or a namespace. +/// is either a type, an expression, a template-name, an attribute or a +/// namespace. class CXXReflectExpr : public Expr { enum class OperandKind { Unset, @@ -5408,12 +5409,12 @@ class CXXReflectExpr : public Expr { /// reflections (P2996). Arguments vary by function. class CXXMetafunctionExpr : public Expr { public: - // Type of callback provided to executing metafunctinons to help evaluate an + // Type of callback provided to executing metafunctions to help evaluate an // expression in the current constant evaluation context. using EvaluateFn = std::function; - // Type of callback provided to report a diagnistc to the evaluation context. + // Type of callback provided to report a diagnostic to the evaluation context. using DiagnoseFn = std::function; diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 9dd8528c04f470..268c8bafdb6c88 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2991,6 +2991,7 @@ DEF_TRAVERSE_STMT(CXXReflectExpr, { case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: + case ReflectionKind::Attribute: // TODO P3385 ? break; } } diff --git a/clang/include/clang/AST/Reflection.h b/clang/include/clang/AST/Reflection.h index 5838d310e00c5f..fde146b47d4240 100644 --- a/clang/include/clang/AST/Reflection.h +++ b/clang/include/clang/AST/Reflection.h @@ -48,7 +48,7 @@ enum class ReflectionKind { /// /// Corresponds to an APValue (plus a QualType). Object, - + /// \brief A reflection of a value (i.e., the result of a prvalue). /// /// Corresponds to an APValue (plus a QualType). @@ -102,8 +102,10 @@ enum class ReflectionKind { /// \brief A reflection of an annotation (P2996 ext). Annotation, -}; + /// \brief A reflection of a standard attribute (P3385). + Attribute, +}; /// \brief Representation of a hypothetical data member, which could be used to /// complete an incomplete class definition using the 'std::meta::define_class' diff --git a/clang/include/clang/Basic/DiagnosticMetafnKinds.td b/clang/include/clang/Basic/DiagnosticMetafnKinds.td index 3bd7a0019a666d..39150bd411d5ef 100644 --- a/clang/include/clang/Basic/DiagnosticMetafnKinds.td +++ b/clang/include/clang/Basic/DiagnosticMetafnKinds.td @@ -18,7 +18,7 @@ def metafn_no_associated_property : Note< "%0 has no %select{type|parent}1">; def metafn_cannot_query_property : Note<"cannot query the " "%select{type|object|value|size|alignment|parameters|return type|" - "annotations}0 of %1">; + "annotations|attributes}0 of %1">; // Ranges of entities. def metafn_cannot_introspect_type : Note< @@ -89,6 +89,11 @@ def metafn_value_not_structural_type : Note< def metafn_result_not_representable : Note< "provided %select{value|object}0 cannot be represented by a reflection">; +def metafn_p3385_trace_execution_checkpoint : Warning< + "(p3385-metafn) trace_execution_checkpoint %0">; +def metafn_p3385_non_standard_attribute : Warning< + "(p3385-metafn) Non standard attribute discovered %0">; + // Class definition. def metafn_name_invalid_identifier : Note< "provided name '%0' is not a valid identifier">; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index f7a9a698911b2a..28ba5a17b349e6 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1746,6 +1746,20 @@ def err_annotation_with_using : Error< "annotations are not permitted following an attribute-using-prefix">; } +let CategoryName = "P3385" in { + +def p3385_trace_attribute_parsed : Warning< + "(p3385) found attribute to parse following caret operator">; +def p3385_trace_empty_attributes_list : Warning< + "(p3385) reflection of an empty attribute list">; +def p3385_trace_execution_checkpoint : Warning< + "(p3385) trace_execution_checkpoint %0">; +def p3385_err_attributes_list : Error< + "(p3385) reflection of attribute list is not supported, found %0 attributes">; +def p3385_err_attribute_splicing_error : Error< + "(p3385) splicing of attributes error: %0">; +} + let CategoryName = "Generics Issue" in { def err_objc_expected_type_parameter : Error< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5db541f3a87eb7..716df4fbcafcc5 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3173,6 +3173,9 @@ def note_dependent_splice_explicit_this_may_fix : Note< def err_cannot_expand_over_type : Error< "cannot expand over an expression of type %0">; +def p3385_trace_building_attribute_reflection : Warning< + "(p3385) building a CXX reflection on attribute %0">; + // C++11 char16_t/char32_t def warn_cxx98_compat_unicode_type : Warning< "'%0' type specifier is incompatible with C++98">, diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index f26e95fcd56b01..4039604838f427 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -316,6 +316,8 @@ class Parser : public CodeCompletionHandler { /// Factory object for creating ParsedAttr objects. AttributeFactory AttrFactory; + /// FIXNE P3385 + ParsedAttributes Attrs; /// Gathers and cleans up TemplateIdAnnotations when parsing of a /// top-level declaration is finished. @@ -3047,6 +3049,11 @@ class Parser : public CodeCompletionHandler { ParseCXX11AttributeSpecifierInternal(Attrs, OpenMPTokens, EndLoc); ReplayOpenMPAttributeTokens(OpenMPTokens); } + + bool tryParseSpliceAttrSpecifier(ParsedAttributes &Attrs, + SourceLocation *EndLoc = nullptr); + /// Try parsing a splice expression when inside an attribute specifier + void ParseCXX11Attributes(ParsedAttributes &attrs); /// Parses a C++11 (or C23)-style attribute argument list. Returns true /// if this results in adding an attribute to the ParsedAttributes list. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 302caa65c0e2d1..e6de857724d7b0 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -35,6 +35,7 @@ #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/AttrSubjectMatchRules.h" +#include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/CapturedStmt.h" #include "clang/Basic/Cuda.h" @@ -15173,6 +15174,7 @@ class Sema final : public SemaBase { ExprResult ActOnCXXReflectExpr(SourceLocation OpLoc, ParsedTemplateArgument Template); ExprResult ActOnCXXReflectExpr(SourceLocation OpLoc, CXXSpliceExpr *E); + ExprResult ActOnCXXReflectExpr(SourceLocation OpLoc, ParsedAttr *a); ExprResult ActOnCXXMetafunction(SourceLocation KwLoc, SourceLocation LParenLoc, @@ -15222,6 +15224,7 @@ class Sema final : public SemaBase { ExprResult BuildCXXReflectExpr(SourceLocation OperatorLoc, SourceLocation OperandLoc, TemplateName Template); + ExprResult BuildCXXReflectExpr(SourceLocation OperatorLoc, ParsedAttr *A); // Reflection of expression operands. ExprResult BuildCXXReflectExpr(SourceLocation OperatorLoc, Expr *E); diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index 3c65393d7e09a4..decb53c9f03caa 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -22,6 +22,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/LocInfoType.h" #include "clang/AST/Type.h" +#include "clang/Basic/AttributeCommonInfo.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -547,6 +548,7 @@ static void profileReflection(llvm::FoldingSetNodeID &ID, APValue V) { case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: ID.AddPointer(V.getOpaqueReflectionData()); return; case ReflectionKind::DataMemberSpec: { @@ -942,6 +944,13 @@ CXX26AnnotationAttr *APValue::getReflectedAnnotation() const { const_cast(getOpaqueReflectionData())); } +AttributeCommonInfo *APValue::getReflectedAttribute() const { + assert(getReflectionKind() == ReflectionKind::Attribute && + "not a reflection of an attribute"); + return reinterpret_cast( + const_cast(getOpaqueReflectionData())); +} + static double GetApproxValue(const llvm::APFloat &F) { llvm::APFloat V = F; bool ignored; @@ -1295,6 +1304,9 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy, case ReflectionKind::Annotation: Repr = "annotation"; break; + case ReflectionKind::Attribute: + Repr = "attribute"; + break; } Out << "^^(" << Repr << ")"; return; @@ -1635,6 +1647,7 @@ void APValue::setReflection(ReflectionKind RK, const void *Ptr) { case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: SelfData.Kind = RK; SelfData.Data = Ptr; return; diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index a2608a5d0dd2a9..73327c39b6e741 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -986,6 +986,7 @@ ExprDependence clang::computeDependence(CXXReflectExpr *E, case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: + case ReflectionKind::Attribute: return ExprDependence::None; } llvm_unreachable("unknown reflection kind while computing dependence"); diff --git a/clang/lib/AST/ExprConstantMeta.cpp b/clang/lib/AST/ExprConstantMeta.cpp index aa1a14ac9ca746..77a2998e8decab 100644 --- a/clang/lib/AST/ExprConstantMeta.cpp +++ b/clang/lib/AST/ExprConstantMeta.cpp @@ -22,7 +22,10 @@ #include "clang/AST/Metafunction.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Reflection.h" +#include "clang/AST/Type.h" +#include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/DiagnosticMetafn.h" +#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" @@ -30,7 +33,6 @@ #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" - namespace clang { using EvalFn = Metafunction::EvaluateFn; @@ -558,6 +560,19 @@ static bool annotate(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, QualType ResultTy, SourceRange Range, ArrayRef Args); +// ----------------------------------------------------------------------------- +// P3385 Metafunction declarations +// ----------------------------------------------------------------------------- + +static bool get_ith_attribute_of(APValue &Result, ASTContext &C, + MetaActions &Meta, EvalFn Evaluator, + DiagFn Diagnoser, QualType ResultTy, + SourceRange Range, + ArrayRef Args); + +static bool is_attribute(APValue &Result, ASTContext &C, MetaActions &Meta, + EvalFn Evaluator, DiagFn Diagnoser, QualType ResultTy, + SourceRange Range, ArrayRef Args); // ----------------------------------------------------------------------------- // Metafunction table @@ -686,6 +701,11 @@ static constexpr Metafunction Metafunctions[] = { { Metafunction::MFRK_metaInfo, 3, 3, get_ith_annotation_of }, { Metafunction::MFRK_bool, 1, 1, is_annotation }, { Metafunction::MFRK_metaInfo, 2, 2, annotate }, + + // P3385 attributes reflection + { Metafunction::MFRK_metaInfo, 3, 3, get_ith_attribute_of }, + { Metafunction::MFRK_bool, 1, 1, is_attribute }, + }; constexpr const unsigned NumMetafunctions = sizeof(Metafunctions) / sizeof(Metafunction); @@ -748,6 +768,10 @@ static APValue makeReflection(CXX26AnnotationAttr *A) { return APValue(ReflectionKind::Annotation, A); } +static APValue makeReflection(const AttributeCommonInfo * Attr) { + return APValue(ReflectionKind::Attribute, Attr); +} + static Expr *makeStrLiteral(StringRef Str, ASTContext &C, bool Utf8) { QualType ConstCharTy = (Utf8 ? C.Char8Ty : C.CharTy).withConst(); @@ -938,6 +962,15 @@ static bool findAnnotLoc(APValue &Result, ASTContext &C, EvalFn Evaluator, return !Evaluator(Result, SLE, true); } +static bool findAttrLoc(APValue &Result, ASTContext &C, EvalFn Evaluator, + QualType ResultTy, AttributeCommonInfo *A) { + SourceLocExpr *SLE = + new (C) SourceLocExpr(C, SourceLocIdentKind::SourceLocStruct, + ResultTy, A->getLoc(), SourceLocation(), + nullptr); + return !Evaluator(Result, SLE, true); +} + static QualType desugarType(QualType QT, bool UnwrapAliases, bool DropCV, bool DropRefs) { bool IsConst = QT.isConstQualified(); @@ -1396,6 +1429,9 @@ StringRef DescriptionOf(APValue RV, bool Granular = true) { case ReflectionKind::Annotation: { return "an annotation"; } + case ReflectionKind::Attribute: { + return "an attribute"; + } } } @@ -1416,6 +1452,82 @@ bool DiagnoseReflectionKind(DiagFn Diagnoser, SourceRange Range, // Metafunction implementations // ----------------------------------------------------------------------------- +bool get_ith_attribute_of(APValue &Result, ASTContext &C, + MetaActions &Meta, EvalFn Evaluator, + DiagFn Diagnoser, QualType ResultTy, + SourceRange Range, ArrayRef Args) { + assert(Args[0]->getType()->isReflectionType()); + assert(ResultTy == C.MetaInfoTy); + + APValue RV; + if (!Evaluator(RV, Args[0], true)) + return true; + + APValue Sentinel; + if (!Evaluator(Sentinel, Args[1], true)) + return true; + assert(Sentinel.isReflectedType()); + + APValue Idx; + if (!Evaluator(Idx, Args[2], true)) + return true; + size_t idx = Idx.getInt().getExtValue(); + + switch (RV.getReflectionKind()) { + case ReflectionKind::Attribute: { + if (idx != 0) { + return SetAndSucceed(Result, Sentinel); + } + AttributeCommonInfo *attr = RV.getReflectedAttribute(); + if (attr->getForm().getSyntax() == AttributeCommonInfo::Syntax::AS_CXX11) { + return SetAndSucceed(Result, makeReflection(attr)); + } + // Non standard + return Diagnoser(Range.getBegin(), diag::metafn_p3385_non_standard_attribute) << attr->getAttrName(); + } + case ReflectionKind::Type: { + QualType qType = RV.getReflectedType(); + Decl *D = findTypeDecl(qType); + if (!D) { + // FIXME how would we end up here ? + return DiagnoseReflectionKind(Diagnoser, Range, "attribute or type", + DescriptionOf(RV)); + } + auto attrs = D->attrs(); + + if (attrs.empty()) { + return SetAndSucceed(Result, Sentinel); + } + + // FIXME cache this... + if (auto* attr = attrs.begin(); attr != attrs.end()) { + while(idx != 0) { + ++attr; + --idx; + if (attr == attrs.end()) { + return SetAndSucceed(Result, Sentinel); + } + } + return SetAndSucceed(Result, makeReflection(*attr)); + } + return SetAndSucceed(Result, Sentinel); + } + case ReflectionKind::Declaration: + case ReflectionKind::Null: + case ReflectionKind::Template: + case ReflectionKind::Object: + case ReflectionKind::Value: + case ReflectionKind::Namespace: + case ReflectionKind::BaseSpecifier: + case ReflectionKind::DataMemberSpec: + case ReflectionKind::Annotation: + return DiagnoseReflectionKind(Diagnoser, Range, "declaration or attribute", + DescriptionOf(RV)); + } + llvm_unreachable("unknown reflection kind"); + return false; +} + bool get_begin_enumerator_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, QualType ResultTy, @@ -1453,6 +1565,7 @@ bool get_begin_enumerator_decl_of(APValue &Result, ASTContext &C, case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: + case ReflectionKind::Attribute: case ReflectionKind::Annotation: { return DiagnoseReflectionKind(Diagnoser, Range, "an enum type", DescriptionOf(RV)); @@ -1493,6 +1606,7 @@ bool get_next_enumerator_decl_of(APValue &Result, ASTContext &C, case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: + case ReflectionKind::Attribute: case ReflectionKind::Annotation: { llvm_unreachable("should have failed in 'get_begin_enumerator_decl_of'"); } @@ -1550,6 +1664,7 @@ bool get_ith_base_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return DiagnoseReflectionKind(Diagnoser, Range, "a class type", DescriptionOf(RV)); } @@ -1604,6 +1719,7 @@ bool get_ith_template_argument_of(APValue &Result, ASTContext &C, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return DiagnoseReflectionKind(Diagnoser, Range, "a template specialization", DescriptionOf(RV)); } @@ -1693,6 +1809,7 @@ bool get_begin_member_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return true; } llvm_unreachable("unknown reflection kind"); @@ -1871,6 +1988,11 @@ bool identifier_of(APValue &Result, ASTContext &C, MetaActions &Meta, getDeclName(Name, C, RV.getReflectedNamespace()); break; } + case ReflectionKind::Attribute: { + AttributeCommonInfo* attr = RV.getReflectedAttribute(); + Name = attr->getAttrName()->getName(); + break; + } case ReflectionKind::DataMemberSpec: { TagDataMemberSpec *TDMS = RV.getReflectedDataMemberSpec(); if (TDMS->Name) @@ -1962,6 +2084,7 @@ bool has_identifier(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: break; } @@ -2049,6 +2172,9 @@ bool source_location_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Annotation: return findAnnotLoc(Result, C, Evaluator, ResultTy, RV.getReflectedAnnotation()); + case ReflectionKind::Attribute: + return findAttrLoc(Result, C, Evaluator, ResultTy, + RV.getReflectedAttribute()); case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Null: @@ -2070,6 +2196,7 @@ bool type_of(APValue &Result, ASTContext &C, MetaActions &Meta, switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Type: + case ReflectionKind::Attribute: case ReflectionKind::Template: case ReflectionKind::Namespace: return Diagnoser(Range.getBegin(), diag::metafn_no_associated_property) @@ -2145,6 +2272,7 @@ bool parent_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: if (Diagnoser) return Diagnoser(Range.getBegin(), diag::metafn_no_associated_property) << DescriptionOf(RV) << 1 << Range; @@ -2198,6 +2326,7 @@ bool dealias(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, RV); case ReflectionKind::Type: { QualType QT = RV.getReflectedType(); @@ -2259,6 +2388,7 @@ bool object_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 1 << DescriptionOf(RV) << Range; } @@ -2348,6 +2478,7 @@ bool value_of(APValue &Result, ASTContext &C, MetaActions &Meta, /*DropCV=*/true, /*DropRefs=*/false); return SetAndSucceed(Result, A->getValue().Lift(Ty)); } + case ReflectionKind::Attribute: // TODO P3385 anything to do ? case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Template: @@ -2395,6 +2526,7 @@ bool template_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return DiagnoseReflectionKind(Diagnoser, Range, "a template specialization", DescriptionOf(RV)); return true; @@ -2417,6 +2549,7 @@ static bool CanActAsTemplateArg(const APValue &RV) { case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: case ReflectionKind::Null: return false; } @@ -2837,6 +2970,7 @@ bool extract(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Type: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::Attribute: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: return Diagnoser(Range.getBegin(), diag::metafn_cannot_extract) @@ -2884,6 +3018,7 @@ bool is_public(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: case ReflectionKind::Namespace: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("invalid reflection type"); @@ -2927,6 +3062,7 @@ bool is_protected(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Value: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: case ReflectionKind::Namespace: return SetAndSucceed(Result, makeBool(C, false)); } @@ -2972,6 +3108,7 @@ bool is_private(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Namespace: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("invalid reflection type"); @@ -3026,6 +3163,7 @@ bool is_access_specified(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Namespace: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("invalid reflection type"); @@ -3134,6 +3272,7 @@ bool is_accessible(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Namespace: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return DiagnoseReflectionKind(Diagnoser, Range, "a class member", DescriptionOf(RV)); } @@ -3169,7 +3308,8 @@ bool is_virtual(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Namespace: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: - return SetAndSucceed(Result, makeBool(C, IsVirtual)); + case ReflectionKind::Attribute: + return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("invalid reflection type"); } @@ -3194,6 +3334,7 @@ bool is_pure_virtual(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Declaration: { bool IsPureVirtual = false; @@ -3227,6 +3368,7 @@ bool is_override(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Declaration: { if (const auto *MD = dyn_cast(RV.getReflectedDecl())) @@ -3257,6 +3399,7 @@ bool is_deleted(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Declaration: { bool IsDeleted = false; @@ -3288,6 +3431,7 @@ bool is_defaulted(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Declaration: { bool IsDefaulted = false; @@ -3319,6 +3463,7 @@ bool is_explicit(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: case ReflectionKind::Template: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Declaration: { @@ -3354,6 +3499,7 @@ bool is_noexcept(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Type: { const QualType QT = RV.getReflectedType(); @@ -3425,6 +3571,7 @@ bool is_const(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Type: { bool result = isConstQualifiedType(RV.getReflectedType()); @@ -3465,6 +3612,7 @@ bool is_volatile(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Type: { bool result = isVolatileQualifiedType(RV.getReflectedType()); @@ -3807,7 +3955,8 @@ bool is_static_member(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: - return SetAndSucceed(Result, makeBool(C, result)); + case ReflectionKind::Attribute: + return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("unknown reflection kind"); } @@ -3851,6 +4000,18 @@ bool is_namespace(APValue &Result, ASTContext &C, MetaActions &Meta, return SetAndSucceed(Result, makeBool(C, RV.isReflectedNamespace())); } +bool is_attribute(APValue &Result, ASTContext &C, MetaActions &Meta, + EvalFn Evaluator, DiagFn Diagnoser, QualType ResultTy, + SourceRange Range, ArrayRef Args) { + assert(Args[0]->getType()->isReflectionType()); + assert(ResultTy == C.BoolTy); + APValue RV; + if (!Evaluator(RV, Args[0], true)) + return true; + + return SetAndSucceed(Result, makeBool(C, RV.isReflectedAttribute())); +} + bool is_function(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, QualType ResultTy, SourceRange Range, ArrayRef Args) { @@ -3927,6 +4088,7 @@ bool is_alias(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("unknown reflection kind"); @@ -3988,6 +4150,7 @@ bool has_complete_definition(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: break; } @@ -4262,6 +4425,7 @@ bool has_template_arguments(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("unknown reflection kind"); @@ -4361,6 +4525,7 @@ bool is_constructor(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Declaration: { bool result = isa(RV.getReflectedDecl()); @@ -4499,6 +4664,7 @@ bool is_destructor(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Declaration: { bool result = isa(RV.getReflectedDecl()); @@ -4528,6 +4694,7 @@ bool is_special_member_function(APValue &Result, ASTContext &C, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Declaration: { bool IsSpecial = false; @@ -4783,6 +4950,7 @@ bool reflect_invoke(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return Diagnoser(Range.getBegin(), diag::metafn_cannot_invoke) << DescriptionOf(FnRefl) << Range; case ReflectionKind::Object: { @@ -5146,6 +5314,7 @@ bool offset_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member", DescriptionOf(RV)); case ReflectionKind::Declaration: { @@ -5202,6 +5371,7 @@ bool size_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 3 << DescriptionOf(RV); } @@ -5228,6 +5398,7 @@ bool bit_offset_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member", DescriptionOf(RV)); case ReflectionKind::Declaration: { @@ -5290,6 +5461,7 @@ bool bit_size_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 3 << DescriptionOf(RV); } @@ -5353,6 +5525,7 @@ bool alignment_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 4 << DescriptionOf(RV) << Range; } @@ -5541,6 +5714,7 @@ bool get_ith_parameter_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return true; } return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) @@ -5576,6 +5750,7 @@ bool has_consistent_identifier(APValue &Result, ASTContext &C, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return has_identifier(Result, C, Meta, Evaluator, Diagnoser, ResultTy, Range, Args); } @@ -5602,6 +5777,7 @@ bool has_ellipsis_parameter(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 5 << DescriptionOf(RV) << Range; case ReflectionKind::Type: @@ -5648,6 +5824,7 @@ bool has_default_argument(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return DiagnoseReflectionKind(Diagnoser, Range, "a function parameter", DescriptionOf(RV)); } @@ -5722,6 +5899,7 @@ bool return_type_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 6 << DescriptionOf(RV) << Range; } @@ -5794,6 +5972,7 @@ bool get_ith_annotation_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 7 << DescriptionOf(RV) << Range; } @@ -5868,6 +6047,7 @@ bool annotate(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: return Diagnoser(Range.getBegin(), diag::metafn_cannot_annotate) << DescriptionOf(Appertainee) << Range; } diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index fe46d6a86da5a4..96bba3244a03d0 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -14,10 +14,13 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyDeclStackTrace.h" +#include "clang/AST/Reflection.h" #include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/Attributes.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/DiagnosticParse.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" @@ -5041,11 +5044,131 @@ bool Parser::ParseCXX11AttributeArgs( return true; } +// FIXME I'm copypasting this straight from ExprConstantMeta +// +static NamedDecl *findTypeDecl(QualType QT) { + // If it's an ElaboratedType, get the underlying NamedType. + if (const ElaboratedType *ET = dyn_cast(QT)) + QT = ET->getNamedType(); + + // Get the type's declaration. + NamedDecl *D = nullptr; + if (auto *TDT = dyn_cast(QT)) + D = TDT->getDecl(); + else if (auto *UT = dyn_cast(QT)) + D = UT->getFoundDecl(); + else if (auto *TD = QT->getAsTagDecl()) + return TD; + else if (auto *TT = dyn_cast(QT)) + D = TT->getDecl(); + else if (auto *UUTD = dyn_cast(QT)) + D = UUTD->getDecl(); + else if (auto *TS = dyn_cast(QT)) { + if (auto *CTD = dyn_cast( + TS->getTemplateName().getAsTemplateDecl())) { + void *InsertPos; + D = CTD->findSpecialization(TS->template_arguments(), InsertPos); + } + } else if (auto *STTP = dyn_cast(QT)) + D = findTypeDecl(STTP->getReplacementType()); + else if (auto *ICNT = dyn_cast(QT)) + D = ICNT->getDecl(); + else if (auto *DTT = dyn_cast(QT)) + D = findTypeDecl(DTT->getUnderlyingType()); + + return D; +} + +// FIXME this is get_attributes, repeated here +// +bool Parser::tryParseSpliceAttrSpecifier(ParsedAttributes &Attrs, + SourceLocation *EndLoc) +{ + // Try parsing a [: meta-info :] immediately following '[' '[' + if (!Tok.is(tok::l_splice)) { + return true; + } + if (ParseCXXSpliceSpecifier()) { + // FIXME diagnostic is terrible... + Diag(Tok.getLocation(), diag::p3385_err_attribute_splicing_error) + << "invalid expression in attribute splicing"; + return true; // yea...Dont know what kind of convention that is + } + if (!Tok.is(tok::annot_splice)) { + return true; + } + Diag(Tok.getLocation(), diag::p3385_trace_execution_checkpoint) + << "Found splice in attribute expression"; + SourceLocation loc = (Tok.getLocation()); + SourceRange range(loc); + + // FIXME What's this doing ? + ExprResult Result = getExprAnnotation(Tok); + ConsumeAnnotationToken(); + + // TODO export to ActOnBlablabla() is the `iDiOmAtIc WaY` + // + auto *SpliceExpr = cast(Result.get()); + Expr::EvalResult ER; + if (!SpliceExpr->EvaluateAsRValue(ER, Actions.getASTContext(), true)) { + return false; + } + + assert(ER.Val.getKind() == APValue::Reflection); + switch (ER.Val.getReflectionKind()) { + case ReflectionKind::Attribute: { + auto * attr = ER.Val.getReflectedAttribute(); + + Attrs.addNew( + const_cast(attr->getAttrName()), // (C) Trust me bro + range, + nullptr, loc, nullptr, 0, + ParsedAttr::Form::CXX11()); + break; + } + case ReflectionKind::Type: { + QualType qType = ER.Val.getReflectedType(); + Decl *D = findTypeDecl(qType); + if (!D) { + // FIXME how would we end up here ? + Diag(Tok.getLocation(), diag::p3385_err_attribute_splicing_error) + << "Error while splicing type attributes inside a [[ ]]"; + } + for (auto *const attr : D->attrs()) { + Attrs.addNew( + const_cast(attr->getAttrName()), // (C) Trust me bro 2 + range, + nullptr, loc, nullptr, 0, + ParsedAttr::Form::CXX11()); + } + break; + } + default: + Diag(Tok.getLocation(), diag::p3385_err_attribute_splicing_error) + << "unsupported kind in attribute splicing"; + } + + // FIXME this shouldnt be here... but we early quit ParseCXX11AttributeSpecifierInternal + // Finish with consuming close ']' '] + SourceLocation CloseLoc = Tok.getLocation(); + if (ExpectAndConsume(tok::r_square)) + SkipUntil(tok::r_square); + else if (Tok.is(tok::r_square)) + checkCompoundToken(CloseLoc, tok::r_square, CompoundToken::AttrEnd); + if (EndLoc) + *EndLoc = Tok.getLocation(); + if (ExpectAndConsume(tok::r_square)) + SkipUntil(tok::r_square); + + return false; +} + /// Parse a C++11 or C23 attribute-specifier. /// /// [C++11] attribute-specifier: /// '[' '[' attribute-list ']' ']' /// alignment-specifier +/// '[' '[' splice-name-qualifier ']' ']' /// /// [C++11] attribute-list: /// attribute[opt] @@ -5151,6 +5274,13 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, SourceLocation ScopeLoc, AttrLoc; IdentifierInfo *ScopeName = nullptr, *AttrName = nullptr; + // Try parsing a `[: :]` expression + if (!tryParseSpliceAttrSpecifier(Attrs, EndLoc)) { + // I'll forget in 10 minutes but... in clang convention, we end up here + // when we actually did succeed... so we quit parsing attributes here. + return; + } + if (Tok.is(tok::equal) && getLangOpts().AnnotationAttributes) { // This is a C++2c annotation. if (CommonScopeName) { diff --git a/clang/lib/Parse/ParseReflect.cpp b/clang/lib/Parse/ParseReflect.cpp index f76bb6b1c7ee73..9b0de2401b5cd1 100644 --- a/clang/lib/Parse/ParseReflect.cpp +++ b/clang/lib/Parse/ParseReflect.cpp @@ -12,10 +12,12 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/Attr.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" +#include "clang/Sema/Ownership.h" using namespace clang; ExprResult Parser::ParseCXXReflectExpression(SourceLocation OpLoc) { @@ -79,6 +81,27 @@ ExprResult Parser::ParseCXXReflectExpression(SourceLocation OpLoc) { } TentativeAction.Revert(); + // Check for a standard attribute + { + size_t last = Attrs.size(); + if (MaybeParseCXX11Attributes(Attrs)) { + size_t newLast = Attrs.size(); + Diag(OperandLoc, diag::p3385_trace_attribute_parsed); + + // FIXME handle empty [[]] gracefully + if (last == newLast) { + Diag(OperandLoc, diag::p3385_trace_empty_attributes_list); + return ExprError(); + } + if (newLast - last > 1) { + Diag(OperandLoc, diag::p3385_err_attributes_list) << (newLast - last); + return ExprError(); + } + + return Actions.ActOnCXXReflectExpr(OpLoc, &Attrs.back()); + } + } + if (SS.isSet() && TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, true, ImplicitTypenameContext::No)) { diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 7f7851cc451536..4e1bd266bd24f2 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -21,6 +21,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/ParsedAttr.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaCodeCompletion.h" @@ -57,7 +58,7 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) : PP(pp), PreferredType(pp.isCodeCompletionEnabled()), Actions(actions), Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), ColonIsSacred(false), InMessageExpression(false), - TemplateParameterDepth(0), ParsingInObjCContainer(false) { + TemplateParameterDepth(0), Attrs(AttrFactory), ParsingInObjCContainer(false) { SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies; Tok.startToken(); Tok.setKind(tok::eof); diff --git a/clang/lib/Sema/SemaReflect.cpp b/clang/lib/Sema/SemaReflect.cpp index 15ccf9cf6396fd..2cd76dc0a8d57f 100644 --- a/clang/lib/Sema/SemaReflect.cpp +++ b/clang/lib/Sema/SemaReflect.cpp @@ -21,6 +21,7 @@ #include "clang/Basic/DiagnosticSema.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Ownership.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Template.h" @@ -741,6 +742,11 @@ ExprResult Sema::ActOnCXXReflectExpr(SourceLocation OperatorLoc, return BuildCXXReflectExpr(OperatorLoc, E); } +ExprResult Sema::ActOnCXXReflectExpr(SourceLocation OperatorLoc, + ParsedAttr *A) { + return BuildCXXReflectExpr(OperatorLoc, A); +} + /// Returns an expression representing the result of a metafunction operating /// on a reflection. ExprResult Sema::ActOnCXXMetafunction(SourceLocation KwLoc, @@ -955,6 +961,10 @@ ParsedTemplateArgument Sema::ActOnTemplateSpliceSpecifierArgument( Diag(Splice->getExprLoc(), diag::err_unsupported_splice_kind) << "data member specs" << 0 << 0; break; + case ReflectionKind::Attribute: + Diag(Splice->getExprLoc(), diag::err_unsupported_splice_kind) + << "attribute" << 0 << 0; + break; } return ParsedTemplateArgument(); } @@ -1127,6 +1137,16 @@ ExprResult Sema::BuildCXXReflectExpr(SourceLocation OperatorLoc, ER.Val); } +ExprResult Sema::BuildCXXReflectExpr(SourceLocation OperatorLoc, + ParsedAttr *A) { + Diag(A->getLoc(), diag::p3385_trace_building_attribute_reflection) + << A->getAttrName()->getName(); + + return CXXReflectExpr::Create( + Context, OperatorLoc, A->getRange(), + APValue{ReflectionKind::Attribute, static_cast(A)}); +} + ExprResult Sema::BuildCXXMetafunctionExpr( SourceLocation KwLoc, SourceLocation LParenLoc, SourceLocation RParenLoc, unsigned MetaFnID, const CXXMetafunctionExpr::ImplFn &Impl, @@ -1481,6 +1501,7 @@ ExprResult Sema::BuildReflectionSpliceExpr( case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: Diag(SpliceOp->getOperand()->getExprLoc(), diag::err_unexpected_reflection_kind_in_splice) << 1 << SpliceOp->getOperand()->getSourceRange(); @@ -1609,6 +1630,7 @@ DeclContext *Sema::TryFindDeclContextOf(const Expr *E) { case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: Diag(E->getExprLoc(), diag::err_expected_class_or_namespace) << "spliced entity" << getLangOpts().CPlusPlus; return nullptr; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 6c38df3143e7dd..5be1edf0490651 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -8968,6 +8968,7 @@ TreeTransform::TransformCXXReflectExpr(CXXReflectExpr *E) { case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: llvm_unreachable("reflect expression should not have this reflection kind"); } llvm_unreachable("invalid reflection"); diff --git a/libcxx/include/experimental/meta b/libcxx/include/experimental/meta index 1a1b322cc88d24..a4c5f78ff37991 100644 --- a/libcxx/include/experimental/meta +++ b/libcxx/include/experimental/meta @@ -381,6 +381,10 @@ template consteval auto is_annotation(info) -> bool; consteval auto annotate(info) -> info; +// Attributes reflection (P3385) +consteval auto is_attribute(info) -> bool; +consteval auto attributes_of(info r) -> vector; + } // namespace reflection_v2 } // namespace meta } // namespace std @@ -538,6 +542,10 @@ enum : unsigned { __metafn_get_ith_annotation_of, __metafn_is_annotation, __metafn_annotate, + + // P3385 attributes reflection + __metafn_get_ith_attribute_of, + __metafn_is_attribute, }; consteval auto __workaround_expand_compiler_builtins(info type) -> info; @@ -748,6 +756,25 @@ struct front_annotation_of { } }; +// TODO #ifdef P3385 feature flag + +struct front_attribute_of { + consteval info operator()(info reflectedEntity) const { + return __metafunction(detail::__metafn_get_ith_attribute_of, + reflectedEntity, LIFT(sentinel), 0); + } +}; + +struct next_attribute_of { + consteval info operator()(auto /*currItrInfo */, info reflectedEntity, + size_t idx) const { + return __metafunction(detail::__metafn_get_ith_attribute_of, + reflectedEntity, LIFT(sentinel), idx); + } +}; + +// TODO #endif P3385 feature flag + } // namespace __range_of_infos // ----------------------------------------------------------------------------- @@ -2174,6 +2201,24 @@ consteval auto annotate(info entity, info val) -> info { #endif // __has_feature(annotation_attributes) +// #ifdef TODO Feature flag for P3385 + +// Returns whether the reflected entity is an attribute. +consteval auto is_attribute(info r) -> bool { + return __metafunction(detail::__metafn_is_attribute, r); +} + +consteval auto attributes_of(info r) -> vector { + using iterator = + __range_of_infos::iterator<__range_of_infos::front_attribute_of, + __range_of_infos::next_attribute_of, + __range_of_infos::map_identity_fn>; + using range = __range_of_infos::range; + auto rng = range{r}; + return vector{rng.begin(), rng.end()}; +} + +// #endif TODO Feature flag for P3385 template [[deprecated("separated into 'reflect_value', 'reflect_result', and "