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