diff --git a/clang-tools-extra/pseudo/lib/grammar/CMakeLists.txt b/clang-tools-extra/pseudo/lib/grammar/CMakeLists.txt --- a/clang-tools-extra/pseudo/lib/grammar/CMakeLists.txt +++ b/clang-tools-extra/pseudo/lib/grammar/CMakeLists.txt @@ -1,10 +1,5 @@ set(LLVM_LINK_COMPONENTS Support) -# This library is used by the clang-pseudo-gen tool which runs at build time. -# Dependencies should be minimal to avoid long dep paths in the build graph. -# It does use clangBasic headers (tok::TokenKind), but linking is not needed. -# We have no transitive dependencies on tablegen files. -list(REMOVE_ITEM LLVM_COMMON_DEPENDS clang-tablegen-targets) add_clang_library(clangPseudoGrammar Grammar.cpp GrammarBNF.cpp diff --git a/clang/docs/InternalsManual.rst b/clang/docs/InternalsManual.rst --- a/clang/docs/InternalsManual.rst +++ b/clang/docs/InternalsManual.rst @@ -2798,12 +2798,12 @@ Parsing of the attribute is determined by the various syntactic forms attributes can take, such as GNU, C++11, and Microsoft style attributes, as well as other information provided by the table definition of the attribute. Ultimately, the -parsed representation of an attribute object is an ``ParsedAttr`` object. +parsed representation of an attribute object is a ``ParsedAttr`` object. These parsed attributes chain together as a list of parsed attributes attached to a declarator or declaration specifier. The parsing of attributes is handled -automatically by Clang, except for attributes spelled as keywords. When -implementing a keyword attribute, the parsing of the keyword and creation of the -``ParsedAttr`` object must be done manually. +automatically by Clang, except for attributes spelled as so-called “custom” +keywords. When implementing a custom keyword attribute, the parsing of the +keyword and creation of the ``ParsedAttr`` object must be done manually. Eventually, ``Sema::ProcessDeclAttributeList()`` is called with a ``Decl`` and a ``ParsedAttr``, at which point the parsed attribute can be transformed @@ -2856,33 +2856,60 @@ empty spelling list is also permissible and may be useful for attributes which are created implicitly. The following spellings are accepted: - ============ ================================================================ - Spelling Description - ============ ================================================================ - ``GNU`` Spelled with a GNU-style ``__attribute__((attr))`` syntax and - placement. - ``CXX11`` Spelled with a C++-style ``[[attr]]`` syntax with an optional - vendor-specific namespace. - ``C2x`` Spelled with a C-style ``[[attr]]`` syntax with an optional - vendor-specific namespace. - ``Declspec`` Spelled with a Microsoft-style ``__declspec(attr)`` syntax. - ``Keyword`` The attribute is spelled as a keyword, and required custom - parsing. - ``GCC`` Specifies two or three spellings: the first is a GNU-style - spelling, the second is a C++-style spelling with the ``gnu`` - namespace, and the third is an optional C-style spelling with - the ``gnu`` namespace. Attributes should only specify this - spelling for attributes supported by GCC. - ``Clang`` Specifies two or three spellings: the first is a GNU-style - spelling, the second is a C++-style spelling with the ``clang`` - namespace, and the third is an optional C-style spelling with - the ``clang`` namespace. By default, a C-style spelling is - provided. - ``Pragma`` The attribute is spelled as a ``#pragma``, and requires custom - processing within the preprocessor. If the attribute is meant to - be used by Clang, it should set the namespace to ``"clang"``. - Note that this spelling is not used for declaration attributes. - ============ ================================================================ + ================== ========================================================= + Spelling Description + ================== ========================================================= + ``GNU`` Spelled with a GNU-style ``__attribute__((attr))`` + syntax and placement. + ``CXX11`` Spelled with a C++-style ``[[attr]]`` syntax with an + optional vendor-specific namespace. + ``C2x`` Spelled with a C-style ``[[attr]]`` syntax with an + optional vendor-specific namespace. + ``Declspec`` Spelled with a Microsoft-style ``__declspec(attr)`` + syntax. + ``CustomKeyword`` The attribute is spelled as a keyword, and requires + custom parsing. + ``RegularKeyword`` The attribute is spelled as a keyword. It can be + used in exactly the places that the standard + ``[[attr]]`` syntax can be used, and appertains to + exactly the same thing that a standard attribute + would appertain to. Lexing and parsing of the keyword + are handled automatically. + ``GCC`` Specifies two or three spellings: the first is a + GNU-style spelling, the second is a C++-style spelling + with the ``gnu`` namespace, and the third is an optional + C-style spelling with the ``gnu`` namespace. Attributes + should only specify this spelling for attributes + supported by GCC. + ``Clang`` Specifies two or three spellings: the first is a + GNU-style spelling, the second is a C++-style spelling + with the ``clang`` namespace, and the third is an + optional C-style spelling with the ``clang`` namespace. + By default, a C-style spelling is provided. + ``Pragma`` The attribute is spelled as a ``#pragma``, and requires + custom processing within the preprocessor. If the + attribute is meant to be used by Clang, it should + set the namespace to ``"clang"``. Note that this + spelling is not used for declaration attributes. + ================== ========================================================= + +The C++ standard specifies that “any [non-standard attribute] that is not +recognized by the implementation is ignored” (``[dcl.attr.grammar]``). +The rule for C is similar. This makes ``CXX11`` and ``C2x`` spellings +unsuitable for attributes that affect the type system, that change the +binary interface of the code, or that have other similar semantic meaning. + +``RegularKeyword`` provides an alternative way of spelling such attributes. +It reuses the production rules for standard attributes, but it applies them +to plain keywords rather than to ``[[…]]`` sequences. Compilers that don't +recognize the keyword are likely to report an error of some kind. + +For example, the ``ArmStreaming`` function type attribute affects +both the type system and the binary interface of the function. +It cannot therefore be spelled ``[[arm::streaming]]``, since compilers +that don't understand ``arm::streaming`` would ignore it and miscompile +the code. ``ArmStreaming`` is instead spelled ``__arm_streaming``, but it +can appear wherever a hypothetical ``[[arm::streaming]]`` could appear. Subjects ~~~~~~~~ diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -315,6 +315,13 @@ : Spelling { bit HasOwnParseRules = hasOwnParseRules; } + +// A keyword that can appear wherever a standard attribute can appear, +// and that appertains to whatever a standard attribute would appertain to. +// This is useful for things that affect semantics but that should otherwise +// be treated like standard attributes. +class RegularKeyword : Keyword {} + // A keyword that has its own individual parsing rules. class CustomKeyword : Keyword {} @@ -2427,6 +2434,11 @@ let Documentation = [AArch64SVEPcsDocs]; } +def ArmStreaming : TypeAttr, TargetSpecificAttr { + let Spellings = [RegularKeyword<"__arm_streaming">]; + let Documentation = [ArmStreamingDocs]; +} + def Pure : InheritableAttr { let Spellings = [GCC<"pure">]; let Documentation = [Undocumented]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -6551,6 +6551,41 @@ }]; } +def ArmStreamingDocs : Documentation { + let Category = DocCatType; + let Content = [{ +.. Note:: This attribute has not been implemented yet, but once it is + implemented, it will behave as described below. + +The ``__arm_streaming`` keyword is only available on AArch64 targets. +It applies to function types and specifies that the function has a +“streaming interface”. This means that: + +* the function requires the Scalable Matrix Extension (SME) + +* the function must be entered in streaming mode (that is, with PSTATE.SM + set to 1) + +* the function must return in streaming mode + +See `Procedure Call Standard for the Arm® 64-bit Architecture (AArch64) +`_ for more details about +streaming-interface functions. + +Clang manages PSTATE.SM automatically; it is not the source code's +responsibility to do this. For example, if a normal non-streaming +function calls an ``__arm_streaming`` function, Clang generates code +that switches into streaming mode before calling the function and +switches back to non-streaming mode on return. + +``__arm_streaming`` can appear anywhere that a standard ``[[…]]`` type +attribute can appear. + +See `Arm C Language Extensions `_ +for more details about this extension, and for other related SME features. + }]; +} + def AlwaysInlineDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h --- a/clang/include/clang/Basic/AttributeCommonInfo.h +++ b/clang/include/clang/Basic/AttributeCommonInfo.h @@ -77,6 +77,7 @@ unsigned SyntaxUsed : 4; unsigned SpellingIndex : 4; unsigned IsAlignas : 1; + unsigned IsRegularKeywordAttribute : 1; protected: static constexpr unsigned SpellingNotCalculated = 0xf; @@ -86,24 +87,29 @@ /// including its syntax and spelling. class Form { public: - constexpr Form(Syntax SyntaxUsed, unsigned SpellingIndex, bool IsAlignas) + constexpr Form(Syntax SyntaxUsed, unsigned SpellingIndex, bool IsAlignas, + bool IsRegularKeywordAttribute) : SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingIndex), - IsAlignas(IsAlignas) {} + IsAlignas(IsAlignas), + IsRegularKeywordAttribute(IsRegularKeywordAttribute) {} constexpr Form(tok::TokenKind Tok) : SyntaxUsed(AS_Keyword), SpellingIndex(SpellingNotCalculated), - IsAlignas(Tok == tok::kw_alignas) {} + IsAlignas(Tok == tok::kw_alignas), + IsRegularKeywordAttribute(tok::isRegularKeywordAttribute(Tok)) {} Syntax getSyntax() const { return Syntax(SyntaxUsed); } unsigned getSpellingIndex() const { return SpellingIndex; } bool isAlignas() const { return IsAlignas; } + bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; } static Form GNU() { return AS_GNU; } static Form CXX11() { return AS_CXX11; } static Form C2x() { return AS_C2x; } static Form Declspec() { return AS_Declspec; } static Form Microsoft() { return AS_Microsoft; } - static Form Keyword(bool IsAlignas) { - return Form(AS_Keyword, SpellingNotCalculated, IsAlignas); + static Form Keyword(bool IsAlignas, bool IsRegularKeywordAttribute) { + return Form(AS_Keyword, SpellingNotCalculated, IsAlignas, + IsRegularKeywordAttribute); } static Form Pragma() { return AS_Pragma; } static Form ContextSensitiveKeyword() { return AS_ContextSensitiveKeyword; } @@ -113,11 +119,12 @@ private: constexpr Form(Syntax SyntaxUsed) : SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated), - IsAlignas(0) {} + IsAlignas(0), IsRegularKeywordAttribute(0) {} unsigned SyntaxUsed : 4; unsigned SpellingIndex : 4; unsigned IsAlignas : 1; + unsigned IsRegularKeywordAttribute : 1; }; AttributeCommonInfo(const IdentifierInfo *AttrName, @@ -127,7 +134,8 @@ ScopeLoc(ScopeLoc), AttrKind(AttrKind), SyntaxUsed(FormUsed.getSyntax()), SpellingIndex(FormUsed.getSpellingIndex()), - IsAlignas(FormUsed.isAlignas()) { + IsAlignas(FormUsed.isAlignas()), + IsRegularKeywordAttribute(FormUsed.isRegularKeywordAttribute()) { assert(SyntaxUsed >= AS_GNU && SyntaxUsed <= AS_Implicit && "Invalid syntax!"); } @@ -154,7 +162,10 @@ Kind getParsedKind() const { return Kind(AttrKind); } Syntax getSyntax() const { return Syntax(SyntaxUsed); } - Form getForm() const { return Form(getSyntax(), SpellingIndex, IsAlignas); } + Form getForm() const { + return Form(getSyntax(), SpellingIndex, IsAlignas, + IsRegularKeywordAttribute); + } const IdentifierInfo *getAttrName() const { return AttrName; } SourceLocation getLoc() const { return AttrRange.getBegin(); } SourceRange getRange() const { return AttrRange; } @@ -191,6 +202,8 @@ return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword; } + bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; } + bool isContextSensitiveKeywordAttribute() const { return SyntaxUsed == AS_ContextSensitiveKeyword; } diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt --- a/clang/include/clang/Basic/CMakeLists.txt +++ b/clang/include/clang/Basic/CMakeLists.txt @@ -35,6 +35,12 @@ SOURCE Attr.td TARGET ClangAttrSubjectMatchRuleList) +clang_tablegen(AttrTokenKinds.inc -gen-clang-attr-token-kinds + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE Attr.td + TARGET ClangAttrTokenKinds + ) + clang_tablegen(AttrHasAttributeImpl.inc -gen-clang-attr-has-attribute-impl -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ SOURCE Attr.td diff --git a/clang/include/clang/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h --- a/clang/include/clang/Basic/TokenKinds.h +++ b/clang/include/clang/Basic/TokenKinds.h @@ -99,6 +99,13 @@ /// Return true if this is an annotation token representing a pragma. bool isPragmaAnnotation(TokenKind K); +inline constexpr bool isRegularKeywordAttribute(TokenKind K) { + return (false +#define KEYWORD_ATTRIBUTE(X) || (K == tok::kw_##X) +#include "clang/Basic/AttrTokenKinds.inc" + ); +} + } // end namespace tok } // end namespace clang diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -748,6 +748,12 @@ KEYWORD(__builtin_available , KEYALL) KEYWORD(__builtin_sycl_unique_stable_name, KEYSYCL) +// Keywords defined by Attr.td. +#ifndef KEYWORD_ATTRIBUTE +#define KEYWORD_ATTRIBUTE(X) KEYWORD(X, KEYALL) +#endif +#include "clang/Basic/AttrTokenKinds.inc" + // Clang-specific keywords enabled only in testing. TESTING_KEYWORD(__unknown_anytype , KEYALL) diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h --- a/clang/include/clang/Lex/Token.h +++ b/clang/include/clang/Lex/Token.h @@ -117,8 +117,13 @@ } /// Return true if this is any of tok::annot_* kind tokens. - bool isAnnotation() const { - return tok::isAnnotation(getKind()); + bool isAnnotation() const { return tok::isAnnotation(getKind()); } + + /// Return true if the token is a keyword that is parsed in the same + /// position as a standard attribute, but that has semantic meaning + /// and so cannot be a true attribute. + bool isRegularKeywordAttribute() const { + return tok::isRegularKeywordAttribute(getKind()); } /// Return a source location identifier for the specified diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1757,6 +1757,11 @@ return; } + if (T->getAttrKind() == attr::ArmStreaming) { + OS << "__arm_streaming"; + return; + } + OS << " __attribute__(("; switch (T->getAttrKind()) { #define TYPE_ATTR(NAME) @@ -1797,6 +1802,7 @@ case attr::CmseNSCall: case attr::AnnotateType: case attr::WebAssemblyFuncref: + case attr::ArmStreaming: llvm_unreachable("This attribute should have been handled already"); case attr::NSReturnsRetained: diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5258,6 +5258,9 @@ case ParsedAttr::AT_AArch64SVEPcs: CC = CC_AArch64SVEPCS; break; + case ParsedAttr::AT_ArmStreaming: + CC = CC_C; // FIXME: placeholder until real SME support is added. + break; case ParsedAttr::AT_AMDGPUKernelCall: CC = CC_AMDGPUKernelCall; break; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -126,6 +126,7 @@ case ParsedAttr::AT_VectorCall: \ case ParsedAttr::AT_AArch64VectorPcs: \ case ParsedAttr::AT_AArch64SVEPcs: \ + case ParsedAttr::AT_ArmStreaming: \ case ParsedAttr::AT_AMDGPUKernelCall: \ case ParsedAttr::AT_MSABI: \ case ParsedAttr::AT_SysVABI: \ @@ -4895,8 +4896,10 @@ // If we're supposed to infer nullability, do so now. if (inferNullability && !inferNullabilityInnerOnlyComplete) { ParsedAttr::Form form = - inferNullabilityCS ? ParsedAttr::Form::ContextSensitiveKeyword() - : ParsedAttr::Form::Keyword(false /*IsAlignAs*/); + inferNullabilityCS + ? ParsedAttr::Form::ContextSensitiveKeyword() + : ParsedAttr::Form::Keyword(false /*IsAlignAs*/, + false /*IsRegularKeywordAttribute*/); ParsedAttr *nullabilityAttr = Pool.create( S.getNullabilityKeyword(*inferNullability), SourceRange(pointerLoc), nullptr, SourceLocation(), nullptr, 0, form); @@ -7710,6 +7713,8 @@ return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_AArch64SVEPcs: return createSimpleAttr(Ctx, Attr); + case ParsedAttr::AT_ArmStreaming: + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_AMDGPUKernelCall: return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_Pcs: { diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -3094,11 +3094,12 @@ bool IsAlignas = (ParsedKind == AttributeCommonInfo::AT_Aligned && Syntax == AttributeCommonInfo::AS_Keyword && SpellingIndex == AlignedAttr::Keyword_alignas); + bool IsRegularKeywordAttribute = Record.readBool(); - AttributeCommonInfo Info( - AttrName, ScopeName, AttrRange, ScopeLoc, - AttributeCommonInfo::Kind(ParsedKind), - {AttributeCommonInfo::Syntax(Syntax), SpellingIndex, IsAlignas}); + AttributeCommonInfo Info(AttrName, ScopeName, AttrRange, ScopeLoc, + AttributeCommonInfo::Kind(ParsedKind), + {AttributeCommonInfo::Syntax(Syntax), SpellingIndex, + IsAlignas, IsRegularKeywordAttribute}); #include "clang/Serialization/AttrPCHRead.inc" diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4378,6 +4378,7 @@ Record.push_back(A->getParsedKind()); Record.push_back(A->getSyntax()); Record.push_back(A->getAttributeSpellingListIndexRaw()); + Record.push_back(A->isRegularKeywordAttribute()); #include "clang/Serialization/AttrPCHWrite.inc" } diff --git a/clang/unittests/AST/AttrTest.cpp b/clang/unittests/AST/AttrTest.cpp --- a/clang/unittests/AST/AttrTest.cpp +++ b/clang/unittests/AST/AttrTest.cpp @@ -168,4 +168,16 @@ } } +TEST(Attr, RegularKeywordAttribute) { + auto AST = clang::tooling::buildASTFromCode(""); + auto &Ctx = AST->getASTContext(); + auto Funcref = clang::WebAssemblyFuncrefAttr::CreateImplicit(Ctx); + EXPECT_EQ(Funcref->getSyntax(), clang::AttributeCommonInfo::AS_Keyword); + ASSERT_FALSE(Funcref->isRegularKeywordAttribute()); + + auto Streaming = clang::ArmStreamingAttr::CreateImplicit(Ctx); + EXPECT_EQ(Streaming->getSyntax(), clang::AttributeCommonInfo::AS_Keyword); + ASSERT_TRUE(Streaming->isRegularKeywordAttribute()); +} + } // namespace diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -2378,6 +2378,11 @@ OS << "#endif // CLANG_ATTR_ACCEPTS_EXPR_PACK\n\n"; } +static bool isRegularKeywordAttribute(const FlattenedSpelling &S) { + return (S.variety() == "Keyword" && + !S.getSpellingRecord().getValueAsBit("HasOwnParseRules")); +} + static void emitFormInitializer(raw_ostream &OS, const FlattenedSpelling &Spelling, StringRef SpellingIndex) { @@ -2385,7 +2390,9 @@ (Spelling.variety() == "Keyword" && Spelling.name() == "alignas"); OS << "{AttributeCommonInfo::AS_" << Spelling.variety() << ", " << SpellingIndex << ", " << (IsAlignas ? "true" : "false") - << " /*IsAlignas*/}"; + << " /*IsAlignas*/, " + << (isRegularKeywordAttribute(Spelling) ? "true" : "false") + << " /*IsRegularKeywordAttribute*/}"; } static void emitAttributes(RecordKeeper &Records, raw_ostream &OS, @@ -3404,6 +3411,26 @@ OS << " .Default(0);\n"; } +// Emits the list of tokens for regular keyword attributes. +void EmitClangAttrTokenKinds(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("A list of tokens generated from the attribute" + " definitions", + OS); + // Assume for now that the same token is not used in multiple regular + // keyword attributes. + for (auto *R : Records.getAllDerivedDefinitions("Attr")) + for (const auto &S : GetFlattenedSpellings(*R)) + if (isRegularKeywordAttribute(S)) { + if (!R->getValueAsListOfDefs("Args").empty()) + PrintError(R->getLoc(), + "RegularKeyword attributes with arguments are not " + "yet supported"); + OS << "KEYWORD_ATTRIBUTE(" + << S.getSpellingRecord().getValueAsString("Name") << ")\n"; + } + OS << "#undef KEYWORD_ATTRIBUTE\n"; +} + // Emits the list of spellings for attributes. void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { emitSourceFileHeader("Code to implement the __has_attribute logic", OS); diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp --- a/clang/utils/TableGen/TableGen.cpp +++ b/clang/utils/TableGen/TableGen.cpp @@ -35,6 +35,7 @@ GenClangAttrSubjectMatchRuleList, GenClangAttrPCHRead, GenClangAttrPCHWrite, + GenClangAttrTokenKinds, GenClangAttrHasAttributeImpl, GenClangAttrSpellingListIndex, GenClangAttrASTVisitor, @@ -131,6 +132,8 @@ "Generate clang PCH attribute reader"), clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write", "Generate clang PCH attribute writer"), + clEnumValN(GenClangAttrTokenKinds, "gen-clang-attr-token-kinds", + "Generate a list of attribute-related clang tokens"), clEnumValN(GenClangAttrHasAttributeImpl, "gen-clang-attr-has-attribute-impl", "Generate a clang attribute spelling list"), @@ -312,6 +315,9 @@ case GenClangAttrPCHWrite: EmitClangAttrPCHWrite(Records, OS); break; + case GenClangAttrTokenKinds: + EmitClangAttrTokenKinds(Records, OS); + break; case GenClangAttrHasAttributeImpl: EmitClangAttrHasAttrImpl(Records, OS); break; diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h --- a/clang/utils/TableGen/TableGenBackends.h +++ b/clang/utils/TableGen/TableGenBackends.h @@ -43,6 +43,8 @@ llvm::raw_ostream &OS); void EmitClangAttrPCHRead(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitClangAttrPCHWrite(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); +void EmitClangAttrTokenKinds(llvm::RecordKeeper &Records, + llvm::raw_ostream &OS); void EmitClangAttrHasAttrImpl(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitClangAttrSpellingListIndex(llvm::RecordKeeper &Records,