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..2c13309857b3ef 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< @@ -88,6 +88,10 @@ def metafn_value_not_structural_type : Note< "values of non-structural type %0 cannot be represented as reflections">; def metafn_result_not_representable : Note< "provided %select{value|object}0 cannot be represented by a reflection">; +def metafn_p3385_trace_execution_checkpoint : Note< + "(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< diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index f7a9a698911b2a..35c710c215ecd1 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1746,6 +1746,19 @@ 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">; + +} + 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/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..84252f8a41735f 100644 --- a/clang/lib/AST/ExprConstantMeta.cpp +++ b/clang/lib/AST/ExprConstantMeta.cpp @@ -22,7 +22,9 @@ #include "clang/AST/Metafunction.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Reflection.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" @@ -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(AttributeCommonInfo *Attr) { + return APValue(ReflectionKind::Attribute, Attr); +} + static Expr *makeStrLiteral(StringRef Str, ASTContext &C, bool Utf8) { QualType ConstCharTy = (Utf8 ? C.Char8Ty : C.CharTy).withConst(); @@ -1396,6 +1420,9 @@ StringRef DescriptionOf(APValue RV, bool Granular = true) { case ReflectionKind::Annotation: { return "an annotation"; } + case ReflectionKind::Attribute: { + return "an attribute"; + } } } @@ -1416,6 +1443,73 @@ 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: { + // We don't allow ^^[[ attribute, attribute]], so when reflected type is + // attribute idx must be 0 + if (idx == 0) { + AttributeCommonInfo *attr = RV.getReflectedAttribute(); + if (attr->getForm().getSyntax() == AttributeCommonInfo::Syntax::AS_CXX11) { + return SetAndSucceed(Result, makeReflection(attr)); + } + Diagnoser(Range.getBegin(), diag::metafn_p3385_non_standard_attribute) << attr->getAttrName(); + } + return SetAndSucceed(Result, Sentinel); + } + case ReflectionKind::Declaration: { + Decl *D = RV.getReflectedDecl(); + auto attrs = C.getDeclAttrs(D); + if (attrs.empty()) { + return SetAndSucceed(Result, Sentinel); + } + if (idx == attrs.size()) { + return SetAndSucceed(Result, Sentinel); + } + + Attr* attr = attrs[idx]; + if (attr->getForm().getSyntax() == AttributeCommonInfo::Syntax::AS_CXX11) { + return SetAndSucceed(Result, makeReflection(attr)); + } + Diagnoser(Range.getBegin(), diag::metafn_p3385_non_standard_attribute) << attr->getAttrName(); + return SetAndSucceed(Result, Sentinel); + } + case ReflectionKind::Type: + 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 +1547,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 +1588,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 +1646,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 +1701,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 +1791,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 +1970,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 +2066,7 @@ bool has_identifier(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: break; } @@ -2070,6 +2175,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 +2251,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 +2305,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 +2367,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 +2457,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 +2505,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 +2528,7 @@ static bool CanActAsTemplateArg(const APValue &RV) { case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::Attribute: case ReflectionKind::Null: return false; } @@ -2884,6 +2996,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"); @@ -3026,6 +3139,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 +3248,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 +3284,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 +3310,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 +3344,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 +3375,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 +3407,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 +3439,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: { @@ -3851,6 +3972,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) { @@ -4262,6 +4395,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 +4495,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 +4634,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 +4664,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; @@ -5146,6 +5283,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 +5340,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 +5367,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 +5430,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 +5494,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 +5683,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 +5719,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 +5746,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 +5793,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 +5868,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 +5941,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 +6016,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/ParseReflect.cpp b/clang/lib/Parse/ParseReflect.cpp index f76bb6b1c7ee73..fbd8c0c9af471e 100644 --- a/clang/lib/Parse/ParseReflect.cpp +++ b/clang/lib/Parse/ParseReflect.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/Attr.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -79,6 +80,26 @@ ExprResult Parser::ParseCXXReflectExpression(SourceLocation OpLoc) { } TentativeAction.Revert(); + // Check for a standard attribute + { + ParsedAttributes attrs(AttrFactory); + if (MaybeParseCXX11Attributes(attrs)) { + Diag(OperandLoc, diag::p3385_trace_attribute_parsed); + + // FIXME handle empty [[]] gracefully + if (attrs.empty()) { + Diag(OperandLoc, diag::p3385_trace_empty_attributes_list); + return ExprError(); + } + if (attrs.size() > 1) { + Diag(OperandLoc, diag::p3385_err_attributes_list) << attrs.size(); + return ExprError(); + } + + return Actions.ActOnCXXReflectExpr(OpLoc, &attrs.front()); + } + } + if (SS.isSet() && TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, true, ImplicitTypenameContext::No)) { diff --git a/clang/lib/Sema/SemaReflect.cpp b/clang/lib/Sema/SemaReflect.cpp index 15ccf9cf6396fd..5e36291a423ac8 100644 --- a/clang/lib/Sema/SemaReflect.cpp +++ b/clang/lib/Sema/SemaReflect.cpp @@ -741,6 +741,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 +960,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 +1136,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 +1500,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 +1629,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 "