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
59using namespace llvm;
60using namespace clang;
61using 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
75namespace {
76class TypeNodeEmitter {
77  RecordKeeper &Records;
78  raw_ostream &Out;
79  const std::vector<Record*> Types;
80  std::vector<StringRef> MacrosToUndef;
81
82public:
83  TypeNodeEmitter(RecordKeeper &records, raw_ostream &out)
84    : Records(records), Out(out),
85      Types(Records.getAllDerivedDefinitions(TypeNodeClassName)) {
86  }
87
88  void emit();
89
90private:
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
103void 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
126void 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
137void 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
176void 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
184void 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
196void TypeNodeEmitter::addMacroToUndef(StringRef macroName) {
197  MacrosToUndef.push_back(macroName);
198}
199
200void TypeNodeEmitter::emitUndefs() {
201  for (auto &macroName : MacrosToUndef) {
202    Out << "#undef " << macroName << "\n";
203  }
204}
205
206void clang::EmitClangTypeNodes(RecordKeeper &records, raw_ostream &out) {
207  TypeNodeEmitter(records, out).emit();
208}
209