brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.0 KiB · 2e1eaef Raw
208 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This tblgen backend emits the node table (the .def file) for Clang10// type nodes.11//12// This file defines the AST type info database. Each type node is13// enumerated by providing its name (e.g., "Builtin" or "Enum") and14// base class (e.g., "Type" or "TagType"). Depending on where in the15// abstract syntax tree the type will show up, the enumeration uses16// 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 clients20//    will need to understand these types.21//22//    ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in23//    the type hierarchy but has no concrete instances.24//25//    NON_CANONICAL_TYPE(Class, Base) - A type that can show up26//    anywhere in the AST but will never be a part of a canonical27//    type. Clients that only need to deal with canonical types28//    (ignoring, e.g., typedefs and other type aliases used for29//    pretty-printing) can ignore these types.30//31//    DEPENDENT_TYPE(Class, Base) - A type that will only show up32//    within a C++ template that has not been instantiated, e.g., a33//    type that is always dependent. Clients that do not need to deal34//    with uninstantiated C++ templates can ignore these types.35//36//    NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) - A type that37//    is non-canonical unless it is dependent.  Defaults to TYPE because38//    it is neither reliably dependent nor reliably non-canonical.39//40// There is a sixth macro, independent of the others.  Most clients41// will not need to use it.42//43//    ALWAYS_CANONICAL_TYPE(Class) - A type which is always identical to its44//    canonical type.  Clients which can operate on such types more efficiently45//    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("no Type records in input!");104 105  emitSourceFileHeader("An x-macro database of Clang type nodes", Out, Records);106 107  // Preamble108  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  // Postmatter121  emitUndefs();122}123 124void TypeNodeEmitter::emitFallbackDefine(StringRef macroName,125                                         StringRef fallbackMacroName,126                                         StringRef args) {127  Out << "#ifndef " << macroName << "\n";128  Out << "#  define " << macroName << args129      << " " << fallbackMacroName << args << "\n";130  Out << "#endif\n";131 132  addMacroToUndef(macroName);133}134 135void TypeNodeEmitter::emitNodeInvocations() {136  TypeNode lastType;137 138  visitASTNodeHierarchy<TypeNode>(Records, [&](TypeNode type, TypeNode base) {139    // If this is the Type node itself, skip it; it can't be handled140    // 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(type.getLoc(),148                        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(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