1 //=== ClangTypeNodesEmitter.cpp - Generate type node tables -----*- C++ -*-===//
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 <set>
56 #include <string>
57 #include <vector>
58
59 using namespace llvm;
60 using namespace clang;
61 using namespace clang::tblgen;
62
63 // These are spellings in the generated output.
64 #define TypeMacroName "TYPE"
65 #define AbstractTypeMacroName "ABSTRACT_TYPE"
66 #define DependentTypeMacroName "DEPENDENT_TYPE"
67 #define NonCanonicalTypeMacroName "NON_CANONICAL_TYPE"
68 #define NonCanonicalUnlessDependentTypeMacroName "NON_CANONICAL_UNLESS_DEPENDENT_TYPE"
69 #define TypeMacroArgs "(Class, Base)"
70 #define LastTypeMacroName "LAST_TYPE"
71 #define LeafTypeMacroName "LEAF_TYPE"
72
73 #define TypeClassName "Type"
74
75 namespace {
76 class TypeNodeEmitter {
77 RecordKeeper &Records;
78 raw_ostream &Out;
79 const std::vector<Record*> Types;
80 std::vector<StringRef> MacrosToUndef;
81
82 public:
TypeNodeEmitter(RecordKeeper & records,raw_ostream & out)83 TypeNodeEmitter(RecordKeeper &records, raw_ostream &out)
84 : Records(records), Out(out),
85 Types(Records.getAllDerivedDefinitions(TypeNodeClassName)) {
86 }
87
88 void emit();
89
90 private:
91 void emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName,
92 StringRef args);
93
94 void emitNodeInvocations();
95 void emitLastNodeInvocation(TypeNode lastType);
96 void emitLeafNodeInvocations();
97
98 void addMacroToUndef(StringRef macroName);
99 void emitUndefs();
100 };
101 }
102
emit()103 void TypeNodeEmitter::emit() {
104 if (Types.empty())
105 PrintFatalError("no Type records in input!");
106
107 emitSourceFileHeader("An x-macro database of Clang type nodes", Out);
108
109 // Preamble
110 addMacroToUndef(TypeMacroName);
111 addMacroToUndef(AbstractTypeMacroName);
112 emitFallbackDefine(AbstractTypeMacroName, TypeMacroName, TypeMacroArgs);
113 emitFallbackDefine(NonCanonicalTypeMacroName, TypeMacroName, TypeMacroArgs);
114 emitFallbackDefine(DependentTypeMacroName, TypeMacroName, TypeMacroArgs);
115 emitFallbackDefine(NonCanonicalUnlessDependentTypeMacroName, TypeMacroName,
116 TypeMacroArgs);
117
118 // Invocations.
119 emitNodeInvocations();
120 emitLeafNodeInvocations();
121
122 // Postmatter
123 emitUndefs();
124 }
125
emitFallbackDefine(StringRef macroName,StringRef fallbackMacroName,StringRef args)126 void TypeNodeEmitter::emitFallbackDefine(StringRef macroName,
127 StringRef fallbackMacroName,
128 StringRef args) {
129 Out << "#ifndef " << macroName << "\n";
130 Out << "# define " << macroName << args
131 << " " << fallbackMacroName << args << "\n";
132 Out << "#endif\n";
133
134 addMacroToUndef(macroName);
135 }
136
emitNodeInvocations()137 void TypeNodeEmitter::emitNodeInvocations() {
138 TypeNode lastType;
139
140 visitASTNodeHierarchy<TypeNode>(Records, [&](TypeNode type, TypeNode base) {
141 // If this is the Type node itself, skip it; it can't be handled
142 // uniformly by metaprograms because it doesn't have a base.
143 if (!base) return;
144
145 // Figure out which macro to use.
146 StringRef macroName;
147 auto setMacroName = [&](StringRef newName) {
148 if (!macroName.empty())
149 PrintFatalError(type.getLoc(),
150 Twine("conflict when computing macro name for "
151 "Type node: trying to use both \"")
152 + macroName + "\" and \"" + newName + "\"");
153 macroName = newName;
154 };
155 if (type.isSubClassOf(AlwaysDependentClassName))
156 setMacroName(DependentTypeMacroName);
157 if (type.isSubClassOf(NeverCanonicalClassName))
158 setMacroName(NonCanonicalTypeMacroName);
159 if (type.isSubClassOf(NeverCanonicalUnlessDependentClassName))
160 setMacroName(NonCanonicalUnlessDependentTypeMacroName);
161 if (type.isAbstract())
162 setMacroName(AbstractTypeMacroName);
163 if (macroName.empty())
164 macroName = TypeMacroName;
165
166 // Generate the invocation line.
167 Out << macroName << "(" << type.getId() << ", "
168 << base.getClassName() << ")\n";
169
170 lastType = type;
171 });
172
173 emitLastNodeInvocation(lastType);
174 }
175
emitLastNodeInvocation(TypeNode type)176 void TypeNodeEmitter::emitLastNodeInvocation(TypeNode type) {
177 // We check that this is non-empty earlier.
178 Out << "#ifdef " LastTypeMacroName "\n"
179 LastTypeMacroName "(" << type.getId() << ")\n"
180 "#undef " LastTypeMacroName "\n"
181 "#endif\n";
182 }
183
emitLeafNodeInvocations()184 void TypeNodeEmitter::emitLeafNodeInvocations() {
185 Out << "#ifdef " LeafTypeMacroName "\n";
186
187 for (TypeNode type : Types) {
188 if (!type.isSubClassOf(LeafTypeClassName)) continue;
189 Out << LeafTypeMacroName "(" << type.getId() << ")\n";
190 }
191
192 Out << "#undef " LeafTypeMacroName "\n"
193 "#endif\n";
194 }
195
addMacroToUndef(StringRef macroName)196 void TypeNodeEmitter::addMacroToUndef(StringRef macroName) {
197 MacrosToUndef.push_back(macroName);
198 }
199
emitUndefs()200 void TypeNodeEmitter::emitUndefs() {
201 for (auto ¯oName : MacrosToUndef) {
202 Out << "#undef " << macroName << "\n";
203 }
204 }
205
EmitClangTypeNodes(RecordKeeper & records,raw_ostream & out)206 void clang::EmitClangTypeNodes(RecordKeeper &records, raw_ostream &out) {
207 TypeNodeEmitter(records, out).emit();
208 }
209