Skip to content

Commit 17e2702

Browse files
committed
Clang AttributeReference: emit entries for "Undocumented" attributes.
Almost all attributes currently marked `Undocumented` are user-facing attributes which _ought_ to be documented, but nobody has written it yet. This change ensures that we at least acknowledge that these attributes exist in the documentation, even if we have no description of their semantics. A new category, `InternalOnly` has been added for those few attributes which are not user-facing, and should remain omitted from the docs.
1 parent cef6586 commit 17e2702

File tree

3 files changed

+67
-44
lines changed

3 files changed

+67
-44
lines changed

clang/docs/InternalsManual.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2920,7 +2920,7 @@ that is named after the attribute being documented.
29202920

29212921
If the attribute is not for public consumption, or is an implicitly-created
29222922
attribute that has no visible spelling, the documentation list can specify the
2923-
``Undocumented`` object. Otherwise, the attribute should have its documentation
2923+
``InternalOnly`` object. Otherwise, the attribute should have its documentation
29242924
added to AttrDocs.td.
29252925

29262926
Documentation derives from the ``Documentation`` tablegen type. All derived

clang/include/clang/Basic/Attr.td

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,19 @@ def DocCatType : DocumentationCategory<"Type Attributes">;
1919
def DocCatStmt : DocumentationCategory<"Statement Attributes">;
2020
def DocCatDecl : DocumentationCategory<"Declaration Attributes">;
2121

22-
// Attributes listed under the Undocumented category do not generate any public
23-
// documentation. Ideally, this category should be used for internal-only
24-
// attributes which contain no spellings.
25-
def DocCatUndocumented : DocumentationCategory<"Undocumented">;
22+
// This category is for attributes which have not yet been properly documented,
23+
// but should be.
24+
def DocCatUndocumented : DocumentationCategory<"Undocumented"> {
25+
let Content = [{
26+
This section lists attributes which are recognized by Clang, but which are
27+
currently missing documentation.
28+
}];
29+
}
30+
31+
// Attributes listed under the InternalOnly category do not generate any entry
32+
// in the documentation. This category should be used only when we _want_
33+
// to not document the attribute, e.g. if the attribute has no spellings.
34+
def DocCatInternalOnly : DocumentationCategory<"InternalOnly">;
2635

2736
class DocDeprecated<string replacement = ""> {
2837
// If the Replacement field is empty, no replacement will be listed with the
@@ -48,11 +57,17 @@ class Documentation {
4857
DocDeprecated Deprecated;
4958
}
5059

51-
// Specifies that the attribute is explicitly undocumented. This can be a
52-
// helpful placeholder for the attribute while working on the implementation,
53-
// but should not be used once feature work has been completed.
60+
// Specifies that the attribute is explicitly omitted from the documentation,
61+
// because it is not intended to be user-facing.
62+
def InternalOnly : Documentation {
63+
let Category = DocCatInternalOnly;
64+
}
65+
66+
// Specifies that the attribute is undocumented, but that it _should_ have
67+
// documentation.
5468
def Undocumented : Documentation {
5569
let Category = DocCatUndocumented;
70+
let Content = "No documentation.";
5671
}
5772

5873
include "clang/Basic/AttrDocs.td"
@@ -626,7 +641,7 @@ class IgnoredAttr : Attr {
626641
let Ignored = 1;
627642
let ASTNode = 0;
628643
let SemaHandler = 0;
629-
let Documentation = [Undocumented];
644+
let Documentation = [InternalOnly];
630645
}
631646

632647
//
@@ -706,14 +721,14 @@ def AlignMac68k : InheritableAttr {
706721
// This attribute has no spellings as it is only ever created implicitly.
707722
let Spellings = [];
708723
let SemaHandler = 0;
709-
let Documentation = [Undocumented];
724+
let Documentation = [InternalOnly];
710725
}
711726

712727
def AlignNatural : InheritableAttr {
713728
// This attribute has no spellings as it is only ever created implicitly.
714729
let Spellings = [];
715730
let SemaHandler = 0;
716-
let Documentation = [Undocumented];
731+
let Documentation = [InternalOnly];
717732
}
718733

719734
def AlwaysInline : DeclOrStmtAttr {
@@ -1188,7 +1203,7 @@ def CUDAInvalidTarget : InheritableAttr {
11881203
let Spellings = [];
11891204
let Subjects = SubjectList<[Function]>;
11901205
let LangOpts = [CUDA];
1191-
let Documentation = [Undocumented];
1206+
let Documentation = [InternalOnly];
11921207
}
11931208

11941209
def CUDALaunchBounds : InheritableAttr {
@@ -1440,7 +1455,9 @@ def Final : InheritableAttr {
14401455
let Spellings = [Keyword<"final">, Keyword<"sealed">];
14411456
let Accessors = [Accessor<"isSpelledAsSealed", [Keyword<"sealed">]>];
14421457
let SemaHandler = 0;
1443-
let Documentation = [Undocumented];
1458+
// Omitted from docs, since this is language syntax, not an attribute, as far
1459+
// as users are concerned.
1460+
let Documentation = [InternalOnly];
14441461
}
14451462

14461463
def MinSize : InheritableAttr {
@@ -1502,8 +1519,6 @@ def GNUInline : InheritableAttr {
15021519
def Hot : InheritableAttr {
15031520
let Spellings = [GCC<"hot">];
15041521
let Subjects = SubjectList<[Function]>;
1505-
// An AST node is created for this attribute, but not actually used beyond
1506-
// semantic checking for mutual exclusion with the Cold attribute.
15071522
let Documentation = [Undocumented];
15081523
let SimpleHandler = 1;
15091524
}
@@ -1582,7 +1597,7 @@ def MaxFieldAlignment : InheritableAttr {
15821597
let Spellings = [];
15831598
let Args = [UnsignedArgument<"Alignment">];
15841599
let SemaHandler = 0;
1585-
let Documentation = [Undocumented];
1600+
let Documentation = [InternalOnly];
15861601
}
15871602

15881603
def MayAlias : InheritableAttr {
@@ -1994,7 +2009,7 @@ def TypeNullUnspecified : TypeAttr {
19942009
// qualifier is as an ObjCOwnership attribute with Kind == "none".
19952010
def ObjCInertUnsafeUnretained : TypeAttr {
19962011
let Spellings = [Keyword<"__unsafe_unretained">];
1997-
let Documentation = [Undocumented];
2012+
let Documentation = [InternalOnly];
19982013
}
19992014

20002015
def ObjCKindOf : TypeAttr {
@@ -2278,7 +2293,9 @@ def Overloadable : Attr {
22782293
def Override : InheritableAttr {
22792294
let Spellings = [Keyword<"override">];
22802295
let SemaHandler = 0;
2281-
let Documentation = [Undocumented];
2296+
// Omitted from docs, since this is language syntax, not an attribute, as far
2297+
// as users are concerned.
2298+
let Documentation = [InternalOnly];
22822299
}
22832300

22842301
def Ownership : InheritableAttr {
@@ -2467,47 +2484,47 @@ def PragmaClangBSSSection : InheritableAttr {
24672484
let Spellings = [];
24682485
let Args = [StringArgument<"Name">];
24692486
let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
2470-
let Documentation = [Undocumented];
2487+
let Documentation = [InternalOnly];
24712488
}
24722489

24732490
def PragmaClangDataSection : InheritableAttr {
24742491
// This attribute has no spellings as it is only ever created implicitly.
24752492
let Spellings = [];
24762493
let Args = [StringArgument<"Name">];
24772494
let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
2478-
let Documentation = [Undocumented];
2495+
let Documentation = [InternalOnly];
24792496
}
24802497

24812498
def PragmaClangRodataSection : InheritableAttr {
24822499
// This attribute has no spellings as it is only ever created implicitly.
24832500
let Spellings = [];
24842501
let Args = [StringArgument<"Name">];
24852502
let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
2486-
let Documentation = [Undocumented];
2503+
let Documentation = [InternalOnly];
24872504
}
24882505

24892506
def PragmaClangRelroSection : InheritableAttr {
24902507
// This attribute has no spellings as it is only ever created implicitly.
24912508
let Spellings = [];
24922509
let Args = [StringArgument<"Name">];
24932510
let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
2494-
let Documentation = [Undocumented];
2511+
let Documentation = [InternalOnly];
24952512
}
24962513

24972514
def StrictFP : InheritableAttr {
24982515
// This attribute has no spellings as it is only ever created implicitly.
24992516
// Function uses strict floating point operations.
25002517
let Spellings = [];
25012518
let Subjects = SubjectList<[Function]>;
2502-
let Documentation = [Undocumented];
2519+
let Documentation = [InternalOnly];
25032520
}
25042521

25052522
def PragmaClangTextSection : InheritableAttr {
25062523
// This attribute has no spellings as it is only ever created implicitly.
25072524
let Spellings = [];
25082525
let Args = [StringArgument<"Name">];
25092526
let Subjects = SubjectList<[Function], ErrorDiag>;
2510-
let Documentation = [Undocumented];
2527+
let Documentation = [InternalOnly];
25112528
}
25122529

25132530
def Sentinel : InheritableAttr {
@@ -3496,7 +3513,7 @@ def DLLExportStaticLocal : InheritableAttr, TargetSpecificAttr<TargetHasDLLImpor
34963513
// the function has local static variables, the function is dllexported too.
34973514
let Spellings = [];
34983515
let Subjects = SubjectList<[Function]>;
3499-
let Documentation = [Undocumented];
3516+
let Documentation = [InternalOnly];
35003517
}
35013518

35023519
def DLLImport : InheritableAttr, TargetSpecificAttr<TargetHasDLLImportExport> {
@@ -3522,7 +3539,7 @@ def DLLImportStaticLocal : InheritableAttr, TargetSpecificAttr<TargetHasDLLImpor
35223539
// attribute is used to determine whether the variables are imported or not.
35233540
let Spellings = [];
35243541
let Subjects = SubjectList<[Function]>;
3525-
let Documentation = [Undocumented];
3542+
let Documentation = [InternalOnly];
35263543
}
35273544

35283545
def SelectAny : InheritableAttr {
@@ -3588,7 +3605,7 @@ def MSVtorDisp : InheritableAttr {
35883605
let AdditionalMembers = [{
35893606
MSVtorDispMode getVtorDispMode() const { return MSVtorDispMode(vdm); }
35903607
}];
3591-
let Documentation = [Undocumented];
3608+
let Documentation = [InternalOnly];
35923609
}
35933610

35943611
def InitSeg : Attr {
@@ -3680,29 +3697,29 @@ def CapturedRecord : InheritableAttr {
36803697
// This attribute has no spellings as it is only ever created implicitly.
36813698
let Spellings = [];
36823699
let SemaHandler = 0;
3683-
let Documentation = [Undocumented];
3700+
let Documentation = [InternalOnly];
36843701
}
36853702

36863703
def OMPThreadPrivateDecl : InheritableAttr {
36873704
// This attribute has no spellings as it is only ever created implicitly.
36883705
let Spellings = [];
36893706
let SemaHandler = 0;
3690-
let Documentation = [Undocumented];
3707+
let Documentation = [InternalOnly];
36913708
}
36923709

36933710
def OMPCaptureNoInit : InheritableAttr {
36943711
// This attribute has no spellings as it is only ever created implicitly.
36953712
let Spellings = [];
36963713
let SemaHandler = 0;
3697-
let Documentation = [Undocumented];
3714+
let Documentation = [InternalOnly];
36983715
}
36993716

37003717
def OMPCaptureKind : Attr {
37013718
// This attribute has no spellings as it is only ever created implicitly.
37023719
let Spellings = [];
37033720
let SemaHandler = 0;
37043721
let Args = [UnsignedArgument<"CaptureKindVal">];
3705-
let Documentation = [Undocumented];
3722+
let Documentation = [InternalOnly];
37063723
let AdditionalMembers = [{
37073724
llvm::omp::Clause getCaptureKind() const {
37083725
return static_cast<llvm::omp::Clause>(getCaptureKindVal());
@@ -3715,7 +3732,7 @@ def OMPReferencedVar : Attr {
37153732
let Spellings = [];
37163733
let SemaHandler = 0;
37173734
let Args = [ExprArgument<"Ref">];
3718-
let Documentation = [Undocumented];
3735+
let Documentation = [InternalOnly];
37193736
}
37203737

37213738
def OMPDeclareSimdDecl : Attr {
@@ -3788,7 +3805,7 @@ def OMPAllocateDecl : InheritableAttr {
37883805
ExprArgument<"Allocator">,
37893806
ExprArgument<"Alignment">
37903807
];
3791-
let Documentation = [Undocumented];
3808+
let Documentation = [InternalOnly];
37923809
}
37933810

37943811
def OMPDeclareVariant : InheritableAttr {
@@ -3945,7 +3962,7 @@ def Builtin : InheritableAttr {
39453962
let Args = [UnsignedArgument<"ID">];
39463963
let Subjects = SubjectList<[Function]>;
39473964
let SemaHandler = 0;
3948-
let Documentation = [Undocumented];
3965+
let Documentation = [InternalOnly];
39493966
}
39503967

39513968
def EnforceTCB : InheritableAttr {

clang/utils/TableGen/ClangAttrEmitter.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4578,7 +4578,8 @@ static void WriteCategoryHeader(const Record *DocCategory,
45784578

45794579
static std::pair<std::string, SpellingList>
45804580
GetAttributeHeadingAndSpellings(const Record &Documentation,
4581-
const Record &Attribute) {
4581+
const Record &Attribute,
4582+
StringRef Cat) {
45824583
// FIXME: there is no way to have a per-spelling category for the attribute
45834584
// documentation. This may not be a limiting factor since the spellings
45844585
// should generally be consistently applied across the category.
@@ -4598,7 +4599,7 @@ GetAttributeHeadingAndSpellings(const Record &Documentation,
45984599
else {
45994600
std::set<std::string> Uniques;
46004601
for (auto I = Spellings.begin(), E = Spellings.end();
4601-
I != E && Uniques.size() <= 1; ++I) {
4602+
I != E; ++I) {
46024603
std::string Spelling =
46034604
std::string(NormalizeNameForSpellingComparison(I->name()));
46044605
Uniques.insert(Spelling);
@@ -4607,6 +4608,11 @@ GetAttributeHeadingAndSpellings(const Record &Documentation,
46074608
// needs.
46084609
if (Uniques.size() == 1)
46094610
Heading = *Uniques.begin();
4611+
// If it's in the undocumented category, just construct a header by
4612+
// concatenating all the spellings. Might not be great, but better than
4613+
// nothing.
4614+
else if (Cat == "Undocumented")
4615+
Heading = llvm::join(Uniques.begin(), Uniques.end(), ", ");
46104616
}
46114617
}
46124618

@@ -4701,19 +4707,19 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) {
47014707
for (const auto *D : Docs) {
47024708
const Record &Doc = *D;
47034709
const Record *Category = Doc.getValueAsDef("Category");
4704-
// If the category is "undocumented", then there cannot be any other
4705-
// documentation categories (otherwise, the attribute would become
4706-
// documented).
4710+
// If the category is "InternalOnly", then there cannot be any other
4711+
// documentation categories (otherwise, the attribute would be
4712+
// emitted into the docs).
47074713
const StringRef Cat = Category->getValueAsString("Name");
4708-
bool Undocumented = Cat == "Undocumented";
4709-
if (Undocumented && Docs.size() > 1)
4714+
bool InternalOnly = Cat == "InternalOnly";
4715+
if (InternalOnly && Docs.size() > 1)
47104716
PrintFatalError(Doc.getLoc(),
4711-
"Attribute is \"Undocumented\", but has multiple "
4717+
"Attribute is \"InternalOnly\", but has multiple "
47124718
"documentation categories");
47134719

4714-
if (!Undocumented)
4720+
if (!InternalOnly)
47154721
SplitDocs[Category].push_back(DocumentationData(
4716-
Doc, Attr, GetAttributeHeadingAndSpellings(Doc, Attr)));
4722+
Doc, Attr, GetAttributeHeadingAndSpellings(Doc, Attr, Cat)));
47174723
}
47184724
}
47194725

0 commit comments

Comments
 (0)