diff options
-rw-r--r-- | clang/include/clang/Basic/AttrDocs.td | 30 | ||||
-rw-r--r-- | clang/utils/TableGen/ClangAttrEmitter.cpp | 165 |
2 files changed, 102 insertions, 93 deletions
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 3798c8e5655..aaa1935e0d7 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -38,6 +38,10 @@ Attributes in Clang .. contents:: :local: +.. |br| raw:: html + + <br/> + Introduction ============ @@ -51,7 +55,7 @@ def SectionDocs : Documentation { The ``section`` attribute allows you to specify a specific section a global variable or function should be in after translation. }]; - let Heading = "section (gnu::section, __declspec(allocate))"; + let Heading = "section, __declspec(allocate)"; } def InitSegDocs : Documentation { @@ -270,7 +274,7 @@ that appears to be capable of returning to its caller. def AssertCapabilityDocs : Documentation { let Category = DocCatFunction; - let Heading = "assert_capability (assert_shared_capability, clang::assert_capability, clang::assert_shared_capability)"; + let Heading = "assert_capability, assert_shared_capability"; let Content = [{ Marks a function that dynamically tests whether a capability is held, and halts the program if it is not held. @@ -279,7 +283,7 @@ the program if it is not held. def AcquireCapabilityDocs : Documentation { let Category = DocCatFunction; - let Heading = "acquire_capability (acquire_shared_capability, clang::acquire_capability, clang::acquire_shared_capability)"; + let Heading = "acquire_capability, acquire_shared_capability"; let Content = [{ Marks a function as acquiring a capability. }]; @@ -287,7 +291,7 @@ Marks a function as acquiring a capability. def TryAcquireCapabilityDocs : Documentation { let Category = DocCatFunction; - let Heading = "try_acquire_capability (try_acquire_shared_capability, clang::try_acquire_capability, clang::try_acquire_shared_capability)"; + let Heading = "try_acquire_capability, try_acquire_shared_capability"; let Content = [{ Marks a function that attempts to acquire a capability. This function may fail to actually acquire the capability; they accept a Boolean value determining @@ -298,7 +302,7 @@ the capability means success (false). def ReleaseCapabilityDocs : Documentation { let Category = DocCatFunction; - let Heading = "release_capability (release_shared_capability, clang::release_capability, clang::release_shared_capability)"; + let Heading = "release_capability, release_shared_capability"; let Content = [{ Marks a function as releasing a capability. }]; @@ -1261,7 +1265,7 @@ of silently falling back on dynamic initialization. def WarnMaybeUnusedDocs : Documentation { let Category = DocCatVariable; - let Heading = "maybe_unused, unused, gnu::unused"; + let Heading = "maybe_unused, unused"; let Content = [{ When passing the ``-Wunused`` flag to Clang, entities that are unused by the program may be diagnosed. The ``[[maybe_unused]]`` (or @@ -1287,7 +1291,7 @@ enumerator, a non-static data member, or a label. def WarnUnusedResultsDocs : Documentation { let Category = DocCatFunction; - let Heading = "nodiscard, warn_unused_result, clang::warn_unused_result, gnu::warn_unused_result"; + let Heading = "nodiscard, warn_unused_result"; let Content = [{ Clang supports the ability to diagnose when the results of a function call expression are discarded under suspicious circumstances. A diagnostic is @@ -1312,7 +1316,7 @@ potentially-evaluated discarded-value expression that is not explicitly cast to def FallthroughDocs : Documentation { let Category = DocCatStmt; - let Heading = "fallthrough, clang::fallthrough"; + let Heading = "fallthrough"; let Content = [{ The ``fallthrough`` (or ``clang::fallthrough``) attribute is used to annotate intentional fall-through @@ -1460,7 +1464,7 @@ on the command line. def MipsLongCallStyleDocs : Documentation { let Category = DocCatFunction; - let Heading = "long_call (gnu::long_call, gnu::far)"; + let Heading = "long_call, far"; let Content = [{ Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``, and ``__attribute__((near))`` attributes on MIPS targets. These attributes may @@ -1481,7 +1485,7 @@ as ``-mlong-calls`` and ``-mno-long-calls``. def MipsShortCallStyleDocs : Documentation { let Category = DocCatFunction; - let Heading = "short_call (gnu::short_call, gnu::near)"; + let Heading = "short_call, near"; let Content = [{ Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``, ``__attribute__((short__call))``, and ``__attribute__((near))`` attributes @@ -1940,7 +1944,7 @@ def NoSanitizeAddressDocs : Documentation { let Category = DocCatFunction; // This function has multiple distinct spellings, and so it requires a custom // heading to be specified. The most common spelling is sufficient. - let Heading = "no_sanitize_address (no_address_safety_analysis, gnu::no_address_safety_analysis, gnu::no_sanitize_address)"; + let Heading = "no_sanitize_address, no_address_safety_analysis"; let Content = [{ .. _langext-address_sanitizer: @@ -2563,7 +2567,6 @@ for further details including limitations of the unroll hints. def OpenCLUnrollHintDocs : Documentation { let Category = DocCatStmt; - let Heading = "__attribute__((opencl_unroll_hint))"; let Content = [{ The opencl_unroll_hint attribute qualifier can be used to specify that a loop (for, while and do loops) can be unrolled. This attribute qualifier can be @@ -2576,7 +2579,6 @@ s6.11.5 for details. def OpenCLIntelReqdSubGroupSizeDocs : Documentation { let Category = DocCatStmt; - let Heading = "__attribute__((intel_reqd_sub_group_size))"; let Content = [{ The optional attribute intel_reqd_sub_group_size can be used to indicate that the kernel must be compiled and executed with the specified subgroup size. When @@ -3396,7 +3398,7 @@ See the RenderScript_ documentation for more information. def XRayDocs : Documentation { let Category = DocCatFunction; - let Heading = "xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument), xray_log_args (clang::xray_log_args)"; + let Heading = "xray_always_instrument, xray_never_instrument, xray_log_args"; let Content = [{ ``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching. diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 706cb4f246c..bf35caa0cc0 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3747,18 +3747,66 @@ void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records, getPragmaAttributeSupport(Records).generateParsingHelpers(OS); } +enum class SpellingKind { + GNU, + CXX11, + C2x, + Declspec, + Microsoft, + Keyword, + Pragma, +}; +static const size_t NumSpellingKinds = (size_t)SpellingKind::Pragma + 1; + +class SpellingList { + std::vector<std::string> Spellings[NumSpellingKinds]; + +public: + ArrayRef<std::string> operator[](SpellingKind K) const { + return Spellings[(size_t)K]; + } + + void add(const Record &Attr, FlattenedSpelling Spelling) { + SpellingKind Kind = StringSwitch<SpellingKind>(Spelling.variety()) + .Case("GNU", SpellingKind::GNU) + .Case("CXX11", SpellingKind::CXX11) + .Case("C2x", SpellingKind::C2x) + .Case("Declspec", SpellingKind::Declspec) + .Case("Microsoft", SpellingKind::Microsoft) + .Case("Keyword", SpellingKind::Keyword) + .Case("Pragma", SpellingKind::Pragma); + std::string Name; + if (!Spelling.nameSpace().empty()) { + switch (Kind) { + case SpellingKind::CXX11: + case SpellingKind::C2x: + Name = Spelling.nameSpace() + "::"; + break; + case SpellingKind::Pragma: + Name = Spelling.nameSpace() + " "; + break; + default: + PrintFatalError(Attr.getLoc(), "Unexpected namespace in spelling"); + } + } + Name += Spelling.name(); + + Spellings[(size_t)Kind].push_back(Name); + } +}; + class DocumentationData { public: const Record *Documentation; const Record *Attribute; std::string Heading; - unsigned SupportedSpellings; + SpellingList SupportedSpellings; DocumentationData(const Record &Documentation, const Record &Attribute, - const std::pair<std::string, unsigned> HeadingAndKinds) + std::pair<std::string, SpellingList> HeadingAndSpellings) : Documentation(&Documentation), Attribute(&Attribute), - Heading(std::move(HeadingAndKinds.first)), - SupportedSpellings(HeadingAndKinds.second) {} + Heading(std::move(HeadingAndSpellings.first)), + SupportedSpellings(std::move(HeadingAndSpellings.second)) {} }; static void WriteCategoryHeader(const Record *DocCategory, @@ -3774,28 +3822,21 @@ static void WriteCategoryHeader(const Record *DocCategory, OS << "\n\n"; } -enum SpellingKind { - GNU = 1 << 0, - CXX11 = 1 << 1, - C2x = 1 << 2, - Declspec = 1 << 3, - Microsoft = 1 << 4, - Keyword = 1 << 5, - Pragma = 1 << 6 -}; - -static std::pair<std::string, unsigned> -GetAttributeHeadingAndSpellingKinds(const Record &Documentation, - const Record &Attribute) { +static std::pair<std::string, SpellingList> +GetAttributeHeadingAndSpellings(const Record &Documentation, + const Record &Attribute) { // FIXME: there is no way to have a per-spelling category for the attribute // documentation. This may not be a limiting factor since the spellings // should generally be consistently applied across the category. std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute); + if (Spellings.empty()) + PrintFatalError(Attribute.getLoc(), + "Attribute has no supported spellings; cannot be " + "documented"); // Determine the heading to be used for this attribute. std::string Heading = Documentation.getValueAsString("Heading"); - bool CustomHeading = !Heading.empty(); if (Heading.empty()) { // If there's only one spelling, we can simply use that. if (Spellings.size() == 1) @@ -3819,51 +3860,11 @@ GetAttributeHeadingAndSpellingKinds(const Record &Documentation, PrintFatalError(Attribute.getLoc(), "This attribute requires a heading to be specified"); - // Gather a list of unique spellings; this is not the same as the semantic - // spelling for the attribute. Variations in underscores and other non- - // semantic characters are still acceptable. - std::vector<std::string> Names; + SpellingList SupportedSpellings; + for (const auto &I : Spellings) + SupportedSpellings.add(Attribute, I); - unsigned SupportedSpellings = 0; - for (const auto &I : Spellings) { - SpellingKind Kind = StringSwitch<SpellingKind>(I.variety()) - .Case("GNU", GNU) - .Case("CXX11", CXX11) - .Case("C2x", C2x) - .Case("Declspec", Declspec) - .Case("Microsoft", Microsoft) - .Case("Keyword", Keyword) - .Case("Pragma", Pragma); - - // Mask in the supported spelling. - SupportedSpellings |= Kind; - - std::string Name; - if ((Kind == CXX11 || Kind == C2x) && !I.nameSpace().empty()) - Name = I.nameSpace() + "::"; - Name += I.name(); - - // If this name is the same as the heading, do not add it. - if (Name != Heading) - Names.push_back(Name); - } - - // Print out the heading for the attribute. If there are alternate spellings, - // then display those after the heading. - if (!CustomHeading && !Names.empty()) { - Heading += " ("; - for (auto I = Names.begin(), E = Names.end(); I != E; ++I) { - if (I != Names.begin()) - Heading += ", "; - Heading += *I; - } - Heading += ")"; - } - if (!SupportedSpellings) - PrintFatalError(Attribute.getLoc(), - "Attribute has no supported spellings; cannot be " - "documented"); - return std::make_pair(std::move(Heading), SupportedSpellings); + return std::make_pair(std::move(Heading), std::move(SupportedSpellings)); } static void WriteDocumentation(RecordKeeper &Records, @@ -3872,23 +3873,29 @@ static void WriteDocumentation(RecordKeeper &Records, // List what spelling syntaxes the attribute supports. OS << ".. csv-table:: Supported Syntaxes\n"; - OS << " :header: \"GNU\", \"C++11\", \"C2x\", \"__declspec\", \"Keyword\","; - OS << " \"Pragma\", \"Pragma clang attribute\"\n\n"; + OS << " :header: \"GNU\", \"C++11\", \"C2x\", \"``__declspec``\","; + OS << " \"Keyword\", \"``#pragma``\", \"``#pragma clang attribute``\"\n\n"; OS << " \""; - if (Doc.SupportedSpellings & GNU) OS << "X"; - OS << "\",\""; - if (Doc.SupportedSpellings & CXX11) OS << "X"; - OS << "\",\""; - if (Doc.SupportedSpellings & C2x) OS << "X"; - OS << "\",\""; - if (Doc.SupportedSpellings & Declspec) OS << "X"; - OS << "\",\""; - if (Doc.SupportedSpellings & Keyword) OS << "X"; - OS << "\", \""; - if (Doc.SupportedSpellings & Pragma) OS << "X"; - OS << "\", \""; - if (getPragmaAttributeSupport(Records).isAttributedSupported(*Doc.Attribute)) - OS << "X"; + for (size_t Kind = 0; Kind != NumSpellingKinds; ++Kind) { + SpellingKind K = (SpellingKind)Kind; + // FIXME: Why are Microsoft spellings not listed? + if (K == SpellingKind::Microsoft) + continue; + + bool PrintedAny = false; + for (StringRef Spelling : Doc.SupportedSpellings[K]) { + if (PrintedAny) + OS << " |br| "; + OS << "``" << Spelling << "``"; + PrintedAny = true; + } + + OS << "\",\""; + } + + if (getPragmaAttributeSupport(Records).isAttributedSupported( + *Doc.Attribute)) + OS << "Yes"; OS << "\"\n\n"; // If the attribute is deprecated, print a message about it, and possibly @@ -3944,7 +3951,7 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) { if (!Undocumented) SplitDocs[Category].push_back(DocumentationData( - Doc, Attr, GetAttributeHeadingAndSpellingKinds(Doc, Attr))); + Doc, Attr, GetAttributeHeadingAndSpellings(Doc, Attr))); } } |