diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h index 21647ffa5ac5a4b..f3ff6f3ff217093 100644 --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -40,6 +40,7 @@ template class BasicReaderBase; class Expr; class FieldDecl; class NamespaceDecl; + class ParsedAttr; struct PrintingPolicy; class Type; class ValueDecl; @@ -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; + ParsedAttr *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 ea12345ea49f553..134c7e49081b3f3 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 9dd8528c04f4706..268c8bafdb6c884 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 5838d310e00c5f8..fde146b47d4240f 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/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 68d0e844780b451..9a8faa3e38aa05b 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -105,6 +105,9 @@ def err_fe_reflection_incompatible_with_blocks : Error< def err_fe_parameter_reflection_without_reflection : Error< "cannot specify '-fparameter-reflection' without '-freflection'">, DefaultFatal; +def err_fe_attribute_reflection_without_reflection : Error< + "cannot specify '-fattribute-reflection' without '-freflection'">, + DefaultFatal; def err_fe_dependency_file_requires_MT : Error< "-dependency-file requires at least one -MT or -MQ option">; def err_fe_invalid_plugin_name : Error< diff --git a/clang/include/clang/Basic/DiagnosticMetafnKinds.td b/clang/include/clang/Basic/DiagnosticMetafnKinds.td index 3bd7a0019a666d9..39150bd411d5efe 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 f7a9a698911b2ad..c2881d828e59951 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1746,6 +1746,22 @@ 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) error while splicing attributes reflection: %0">; +def p3385_err_attribute_splicing_with_using_namespace_error : Error< + "(p3385) using prefix with splice expression is not supported: %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 5db541f3a87eb79..716df4fbcafcc5a 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/Basic/Features.def b/clang/include/clang/Basic/Features.def index 4f826ac0b1cc0a7..f0941542cbfbe90 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -310,6 +310,7 @@ FEATURE(cxx_abi_relative_vtable, LangOpts.CPlusPlus && LangOpts.RelativeCXXABIVT FEATURE(reflection, LangOpts.Reflection) FEATURE(reflection_new_syntax, LangOpts.ReflectionNewSyntax) FEATURE(parameter_reflection, LangOpts.ParameterReflection) +FEATURE(attribute_reflection, LangOpts.AttributeReflection) FEATURE(expansion_statements, LangOpts.ExpansionStatements) FEATURE(annotation_attributes, LangOpts.AnnotationAttributes) FEATURE(consteval_blocks, LangOpts.ConstevalBlocks) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index b30ecdf17175c1f..e0ed057032c0743 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -314,6 +314,7 @@ LANGOPT(OpenACC , 1, 0, "OpenACC Enabled") LANGOPT(Reflection , 1, 0, "Experimental C++26 Reflection") LANGOPT(ReflectionNewSyntax , 1, 0, "New syntax for C++26 Reflection") LANGOPT(ParameterReflection , 1, 0, "Augments C++26 Reflection with function parameter reflection") +LANGOPT(AttributeReflection , 1, 0, "Augments C++26 Reflection with standard attribute reflection") LANGOPT(ExpansionStatements , 1, 0, "Experimental C++26 Expansion Statements") LANGOPT(AnnotationAttributes, 1, 0, "Experimental C++26 support for annotations") LANGOPT(ConstevalBlocks, 1, 0, "Experimental C++26 support for consteval blocks") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 255d2ef84a55a77..67a6f1056d30bf2 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3504,6 +3504,11 @@ defm parameter_reflection : BoolFOption<"parameter-reflection", PosFlag, NegFlag>; +defm attribute_reflection : BoolFOption<"attribute-reflection", + LangOpts<"AttributeReflection">, DefaultFalse, + PosFlag, + NegFlag>; defm expansion_statements : BoolFOption<"expansion-statements", LangOpts<"ExpansionStatements">, DefaultFalse, PosFlag(getOpaqueReflectionData())); } +ParsedAttr *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 +1305,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 +1648,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 a2608a5d0dd2a96..73327c39b6e7415 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 aa1a14ac9ca7467..31ebda8df684a61 100644 --- a/clang/lib/AST/ExprConstantMeta.cpp +++ b/clang/lib/AST/ExprConstantMeta.cpp @@ -22,15 +22,18 @@ #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" +#include "clang/Sema/ParsedAttr.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" - namespace clang { using EvalFn = Metafunction::EvaluateFn; @@ -558,6 +561,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 +702,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 +769,10 @@ static APValue makeReflection(CXX26AnnotationAttr *A) { return APValue(ReflectionKind::Annotation, A); } +static APValue makeReflection(const ParsedAttr * 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 +963,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 +1430,9 @@ StringRef DescriptionOf(APValue RV, bool Granular = true) { case ReflectionKind::Annotation: { return "an annotation"; } + case ReflectionKind::Attribute: { + return "an attribute"; + } } } @@ -1412,10 +1449,109 @@ bool DiagnoseReflectionKind(DiagFn Diagnoser, SourceRange Range, return true; } +struct AttributeScratchpad { + AttributeFactory factory; + ParsedAttributes attributes; + AttributeScratchpad() : factory(), attributes(factory) {} +}; + // ----------------------------------------------------------------------------- // 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); + } + ParsedAttr *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 this assumes we arent decorating them with anything besides CXX11 attributes + if (Attr *const *attr = attrs.begin(); attr != attrs.end()) { + while (idx != 0) { + ++attr; + --idx; + if (attr == attrs.end()) { + return SetAndSucceed(Result, Sentinel); + } + } + // Attr -> ParsedAttr + Attr * const val = *attr; + static AttributeScratchpad scratchpad; + + if (val->getForm().getSyntax() != AttributeCommonInfo::Syntax::AS_CXX11) { + // FIXME Filter them instead of erroring + return DiagnoseReflectionKind(Diagnoser, Range, "a standard CXX11 attribute", + DescriptionOf(RV)); + } + auto * fetchedAttribute = scratchpad.attributes.addNew( + const_cast(val->getAttrName()), // FIXME... + val->getRange(), + nullptr, + val->getLocation(), + nullptr, nullptr, nullptr, + val->getForm()); + + return SetAndSucceed(Result, makeReflection(fetchedAttribute)); + } + 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 +1589,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 +1630,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 +1688,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 +1743,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 +1833,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 +2012,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) @@ -1957,6 +2103,11 @@ bool has_identifier(APValue &Result, ASTContext &C, MetaActions &Meta, HasIdentifier = TDMS->Name && !TDMS->Name->empty(); break; } + case ReflectionKind::Attribute: { + // FIXME deal with ^^ [[ ]] + HasIdentifier = true; + break; + } case ReflectionKind::Null: case ReflectionKind::BaseSpecifier: case ReflectionKind::Object: @@ -2049,6 +2200,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 +2224,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 +2300,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 +2354,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 +2416,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 +2506,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 +2554,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 +2577,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 +2998,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 +3046,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 +3090,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 +3136,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 +3191,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 +3300,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 +3336,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 +3362,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 +3396,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 +3427,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 +3459,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 +3491,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 +3527,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 +3599,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 +3640,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 +3983,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 +4028,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 +4116,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 +4178,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 +4453,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 +4553,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 +4692,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 +4722,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 +4978,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 +5342,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 +5399,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 +5426,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 +5489,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 +5553,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 +5742,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 +5778,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 +5805,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 +5852,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 +5927,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 +6000,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 +6075,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/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 0c85156489e49c6..7e287626a7cc752 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7416,6 +7416,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fparameter-reflection is likewise off by default. Args.addOptInFlag(CmdArgs, options::OPT_fparameter_reflection, options::OPT_fno_parameter_reflection); + // -fattribute-reflection is likewise off by default. + Args.addOptInFlag(CmdArgs, options::OPT_fattribute_reflection, + options::OPT_fno_attribute_reflection); // -fexpansion-statements is likewise off by default. Args.addOptInFlag(CmdArgs, options::OPT_fexpansion_statements, options::OPT_fno_expansion_statements); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 7e9119f27857b1f..c40a7d4cb122f98 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -615,8 +615,12 @@ static bool FixupInvocation(CompilerInvocation &Invocation, if (LangOpts.Reflection) { if (LangOpts.Blocks && !LangOpts.ReflectionNewSyntax) Diags.Report(diag::err_fe_reflection_incompatible_with_blocks); - } else if (LangOpts.ParameterReflection) { - Diags.Report(diag::err_fe_parameter_reflection_without_reflection); + } else { + if (LangOpts.ParameterReflection) { + Diags.Report(diag::err_fe_parameter_reflection_without_reflection); + } else if (LangOpts.AttributeReflection) { + Diags.Report(diag::err_fe_attribute_reflection_without_reflection); + } } // The -f[no-]raw-string-literals option is only valid in C and in C++ diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index fe46d6a86da5a4b..8dc030a7488dfa8 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" @@ -32,6 +35,7 @@ #include "clang/Sema/SemaCodeCompletion.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/TimeProfiler.h" +#include #include using namespace clang; @@ -5041,11 +5045,145 @@ 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(!getLangOpts().AttributeReflection) { + Diag(Tok.getLocation(), diag::p3385_err_attribute_splicing_error) + << "attribute splicing is gated behind -fattribute-reflection"; + SkipUntil(tok::r_splice); + ExpectAndConsume(tok::r_splice); + } + + if (ParseCXXSpliceSpecifier()) { + // FIXME diagnostic is terrible... + Diag(Tok.getLocation(), diag::p3385_err_attribute_splicing_error) + << "invalid expression in attribute splicing"; + return true; + } + 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 offload 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(); + ArgsVector ArgExprs; + if (attr->getNumArgs() != 0) { + Diag(Tok.getLocation(), diag::p3385_trace_execution_checkpoint) + << "Found argument while splicing a reflected attribute"; + ArgExprs.push_back(attr->getArg(0)); + } + Attrs.addNew( + const_cast(attr->getAttrName()), // (C) Trust me bro + range, + nullptr, loc, ArgExprs.data(), ArgExprs.size(), + ParsedAttr::Form::CXX11()); + break; + } + case ReflectionKind::Type: { + QualType qType = ER.Val.getReflectedType(); + NamedDecl *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 [[ ]]"; + return true; + } + // FIXME we have an issue here , an 'attr' no longer has arguments, only 'parsedAttr' do + 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"; + } + + // This doesnt really belong 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] @@ -5115,7 +5253,8 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, SourceLocation CommonScopeLoc; IdentifierInfo *CommonScopeName = nullptr; - if (Tok.is(tok::kw_using)) { + bool hasAttributeUsing = Tok.is(tok::kw_using); + if (hasAttributeUsing) { Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_using_attribute_ns : diag::ext_using_attribute_ns); @@ -5132,6 +5271,18 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, Diag(Tok.getLocation(), diag::err_expected) << tok::colon; } + // Try parsing a `[: :]` expression + if (!tryParseSpliceAttrSpecifier(Attrs, EndLoc)) { + if (hasAttributeUsing) { + Diag(Tok.getLocation(), diag::p3385_err_attribute_splicing_with_using_namespace_error) + << "Using prefix is not supported alongside a splice expression in attributes"; + return; + } + // 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; + } + bool AttrParsed = false; while (!Tok.isOneOf(tok::r_square, tok::semi, tok::eof, tok::r_splice)) { if (AttrParsed) { @@ -5151,6 +5302,8 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, SourceLocation ScopeLoc, AttrLoc; IdentifierInfo *ScopeName = nullptr, *AttrName = nullptr; + + 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 f76bb6b1c7ee73b..9b0de2401b5cd11 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 7f7851cc4515363..4e1bd266bd24f2e 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 15ccf9cf6396fdc..2cd76dc0a8d57f4 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 6c38df3143e7dd1..5be1edf04906510 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 1a1b322cc88d247..a4c5f78ff379913 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 "