1 | //===-- ClangTypeNodesEmitter.cpp - Generate type node tables -------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This tblgen backend emits the node table (the .def file) for Clang |
10 | // type nodes. |
11 | // |
12 | // This file defines the AST type info database. Each type node is |
13 | // enumerated by providing its name (e.g., "Builtin" or "Enum") and |
14 | // base class (e.g., "Type" or "TagType"). Depending on where in the |
15 | // abstract syntax tree the type will show up, the enumeration uses |
16 | // one of five different macros: |
17 | // |
18 | // TYPE(Class, Base) - A type that can show up anywhere in the AST, |
19 | // and might be dependent, canonical, or non-canonical. All clients |
20 | // will need to understand these types. |
21 | // |
22 | // ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in |
23 | // the type hierarchy but has no concrete instances. |
24 | // |
25 | // NON_CANONICAL_TYPE(Class, Base) - A type that can show up |
26 | // anywhere in the AST but will never be a part of a canonical |
27 | // type. Clients that only need to deal with canonical types |
28 | // (ignoring, e.g., typedefs and other type aliases used for |
29 | // pretty-printing) can ignore these types. |
30 | // |
31 | // DEPENDENT_TYPE(Class, Base) - A type that will only show up |
32 | // within a C++ template that has not been instantiated, e.g., a |
33 | // type that is always dependent. Clients that do not need to deal |
34 | // with uninstantiated C++ templates can ignore these types. |
35 | // |
36 | // NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) - A type that |
37 | // is non-canonical unless it is dependent. Defaults to TYPE because |
38 | // it is neither reliably dependent nor reliably non-canonical. |
39 | // |
40 | // There is a sixth macro, independent of the others. Most clients |
41 | // will not need to use it. |
42 | // |
43 | // LEAF_TYPE(Class) - A type that never has inner types. Clients |
44 | // which can operate on such types more efficiently may wish to do so. |
45 | // |
46 | //===----------------------------------------------------------------------===// |
47 | |
48 | #include "ASTTableGen.h" |
49 | #include "TableGenBackends.h" |
50 | |
51 | #include "llvm/ADT/StringRef.h" |
52 | #include "llvm/TableGen/Error.h" |
53 | #include "llvm/TableGen/Record.h" |
54 | #include "llvm/TableGen/TableGenBackend.h" |
55 | #include <vector> |
56 | |
57 | using namespace llvm; |
58 | using namespace clang; |
59 | using namespace clang::tblgen; |
60 | |
61 | // These are spellings in the generated output. |
62 | #define TypeMacroName "TYPE" |
63 | #define AbstractTypeMacroName "ABSTRACT_TYPE" |
64 | #define DependentTypeMacroName "DEPENDENT_TYPE" |
65 | #define NonCanonicalTypeMacroName "NON_CANONICAL_TYPE" |
66 | #define NonCanonicalUnlessDependentTypeMacroName "NON_CANONICAL_UNLESS_DEPENDENT_TYPE" |
67 | #define TypeMacroArgs "(Class, Base)" |
68 | #define LastTypeMacroName "LAST_TYPE" |
69 | #define LeafTypeMacroName "LEAF_TYPE" |
70 | |
71 | #define TypeClassName "Type" |
72 | |
73 | namespace { |
74 | class TypeNodeEmitter { |
75 | const RecordKeeper &Records; |
76 | raw_ostream &Out; |
77 | ArrayRef<const Record *> Types; |
78 | std::vector<StringRef> MacrosToUndef; |
79 | |
80 | public: |
81 | TypeNodeEmitter(const RecordKeeper &records, raw_ostream &out) |
82 | : Records(records), Out(out), |
83 | Types(Records.getAllDerivedDefinitions(TypeNodeClassName)) {} |
84 | |
85 | void emit(); |
86 | |
87 | private: |
88 | void emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName, |
89 | StringRef args); |
90 | |
91 | void emitNodeInvocations(); |
92 | void emitLastNodeInvocation(TypeNode lastType); |
93 | void emitLeafNodeInvocations(); |
94 | |
95 | void addMacroToUndef(StringRef macroName); |
96 | void emitUndefs(); |
97 | }; |
98 | } |
99 | |
100 | void TypeNodeEmitter::emit() { |
101 | if (Types.empty()) |
102 | PrintFatalError(Msg: "no Type records in input!" ); |
103 | |
104 | emitSourceFileHeader(Desc: "An x-macro database of Clang type nodes" , OS&: Out, Record: Records); |
105 | |
106 | // Preamble |
107 | addMacroToUndef(TypeMacroName); |
108 | addMacroToUndef(AbstractTypeMacroName); |
109 | emitFallbackDefine(AbstractTypeMacroName, TypeMacroName, TypeMacroArgs); |
110 | emitFallbackDefine(NonCanonicalTypeMacroName, TypeMacroName, TypeMacroArgs); |
111 | emitFallbackDefine(DependentTypeMacroName, TypeMacroName, TypeMacroArgs); |
112 | emitFallbackDefine(NonCanonicalUnlessDependentTypeMacroName, TypeMacroName, |
113 | TypeMacroArgs); |
114 | |
115 | // Invocations. |
116 | emitNodeInvocations(); |
117 | emitLeafNodeInvocations(); |
118 | |
119 | // Postmatter |
120 | emitUndefs(); |
121 | } |
122 | |
123 | void TypeNodeEmitter::emitFallbackDefine(StringRef macroName, |
124 | StringRef fallbackMacroName, |
125 | StringRef args) { |
126 | Out << "#ifndef " << macroName << "\n" ; |
127 | Out << "# define " << macroName << args |
128 | << " " << fallbackMacroName << args << "\n" ; |
129 | Out << "#endif\n" ; |
130 | |
131 | addMacroToUndef(macroName); |
132 | } |
133 | |
134 | void TypeNodeEmitter::emitNodeInvocations() { |
135 | TypeNode lastType; |
136 | |
137 | visitASTNodeHierarchy<TypeNode>(records: Records, visit: [&](TypeNode type, TypeNode base) { |
138 | // If this is the Type node itself, skip it; it can't be handled |
139 | // uniformly by metaprograms because it doesn't have a base. |
140 | if (!base) return; |
141 | |
142 | // Figure out which macro to use. |
143 | StringRef macroName; |
144 | auto setMacroName = [&](StringRef newName) { |
145 | if (!macroName.empty()) |
146 | PrintFatalError(ErrorLoc: type.getLoc(), |
147 | Msg: Twine("conflict when computing macro name for " |
148 | "Type node: trying to use both \"" ) |
149 | + macroName + "\" and \"" + newName + "\"" ); |
150 | macroName = newName; |
151 | }; |
152 | if (type.isSubClassOf(AlwaysDependentClassName)) |
153 | setMacroName(DependentTypeMacroName); |
154 | if (type.isSubClassOf(NeverCanonicalClassName)) |
155 | setMacroName(NonCanonicalTypeMacroName); |
156 | if (type.isSubClassOf(NeverCanonicalUnlessDependentClassName)) |
157 | setMacroName(NonCanonicalUnlessDependentTypeMacroName); |
158 | if (type.isAbstract()) |
159 | setMacroName(AbstractTypeMacroName); |
160 | if (macroName.empty()) |
161 | macroName = TypeMacroName; |
162 | |
163 | // Generate the invocation line. |
164 | Out << macroName << "(" << type.getId() << ", " |
165 | << base.getClassName() << ")\n" ; |
166 | |
167 | lastType = type; |
168 | }); |
169 | |
170 | emitLastNodeInvocation(lastType); |
171 | } |
172 | |
173 | void TypeNodeEmitter::emitLastNodeInvocation(TypeNode type) { |
174 | // We check that this is non-empty earlier. |
175 | Out << "#ifdef " LastTypeMacroName "\n" |
176 | LastTypeMacroName "(" << type.getId() << ")\n" |
177 | "#undef " LastTypeMacroName "\n" |
178 | "#endif\n" ; |
179 | } |
180 | |
181 | void TypeNodeEmitter::emitLeafNodeInvocations() { |
182 | Out << "#ifdef " LeafTypeMacroName "\n" ; |
183 | |
184 | for (TypeNode type : Types) { |
185 | if (!type.isSubClassOf(LeafTypeClassName)) continue; |
186 | Out << LeafTypeMacroName "(" << type.getId() << ")\n" ; |
187 | } |
188 | |
189 | Out << "#undef " LeafTypeMacroName "\n" |
190 | "#endif\n" ; |
191 | } |
192 | |
193 | void TypeNodeEmitter::addMacroToUndef(StringRef macroName) { |
194 | MacrosToUndef.push_back(x: macroName); |
195 | } |
196 | |
197 | void TypeNodeEmitter::emitUndefs() { |
198 | for (auto ¯oName : MacrosToUndef) { |
199 | Out << "#undef " << macroName << "\n" ; |
200 | } |
201 | } |
202 | |
203 | void clang::EmitClangTypeNodes(const RecordKeeper &records, raw_ostream &out) { |
204 | TypeNodeEmitter(records, out).emit(); |
205 | } |
206 | |