//=== ClangTypeNodesEmitter.cpp - Generate type node tables -----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This tblgen backend emits the node table (the .def file) for Clang // type nodes. // // This file defines the AST type info database. Each type node is // enumerated by providing its name (e.g., "Builtin" or "Enum") and // base class (e.g., "Type" or "TagType"). Depending on where in the // abstract syntax tree the type will show up, the enumeration uses // one of five different macros: // // TYPE(Class, Base) - A type that can show up anywhere in the AST, // and might be dependent, canonical, or non-canonical. All clients // will need to understand these types. // // ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in // the type hierarchy but has no concrete instances. // // NON_CANONICAL_TYPE(Class, Base) - A type that can show up // anywhere in the AST but will never be a part of a canonical // type. Clients that only need to deal with canonical types // (ignoring, e.g., typedefs and other type aliases used for // pretty-printing) can ignore these types. // // DEPENDENT_TYPE(Class, Base) - A type that will only show up // within a C++ template that has not been instantiated, e.g., a // type that is always dependent. Clients that do not need to deal // with uninstantiated C++ templates can ignore these types. // // NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) - A type that // is non-canonical unless it is dependent. Defaults to TYPE because // it is neither reliably dependent nor reliably non-canonical. // // There is a sixth macro, independent of the others. Most clients // will not need to use it. // // LEAF_TYPE(Class) - A type that never has inner types. Clients // which can operate on such types more efficiently may wish to do so. // //===----------------------------------------------------------------------===// #include "ASTTableGen.h" #include "TableGenBackends.h" #include "llvm/ADT/StringRef.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include #include #include using namespace llvm; using namespace clang; using namespace clang::tblgen; // These are spellings in the generated output. #define TypeMacroName "TYPE" #define AbstractTypeMacroName "ABSTRACT_TYPE" #define DependentTypeMacroName "DEPENDENT_TYPE" #define NonCanonicalTypeMacroName "NON_CANONICAL_TYPE" #define NonCanonicalUnlessDependentTypeMacroName "NON_CANONICAL_UNLESS_DEPENDENT_TYPE" #define TypeMacroArgs "(Class, Base)" #define LastTypeMacroName "LAST_TYPE" #define LeafTypeMacroName "LEAF_TYPE" #define TypeClassName "Type" namespace { class TypeNodeEmitter { RecordKeeper &Records; raw_ostream &Out; const std::vector Types; std::vector MacrosToUndef; public: TypeNodeEmitter(RecordKeeper &records, raw_ostream &out) : Records(records), Out(out), Types(Records.getAllDerivedDefinitions(TypeNodeClassName)) { } void emit(); private: void emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName, StringRef args); void emitNodeInvocations(); void emitLastNodeInvocation(TypeNode lastType); void emitLeafNodeInvocations(); void addMacroToUndef(StringRef macroName); void emitUndefs(); }; } void TypeNodeEmitter::emit() { if (Types.empty()) PrintFatalError("no Type records in input!"); emitSourceFileHeader("An x-macro database of Clang type nodes", Out); // Preamble addMacroToUndef(TypeMacroName); addMacroToUndef(AbstractTypeMacroName); emitFallbackDefine(AbstractTypeMacroName, TypeMacroName, TypeMacroArgs); emitFallbackDefine(NonCanonicalTypeMacroName, TypeMacroName, TypeMacroArgs); emitFallbackDefine(DependentTypeMacroName, TypeMacroName, TypeMacroArgs); emitFallbackDefine(NonCanonicalUnlessDependentTypeMacroName, TypeMacroName, TypeMacroArgs); // Invocations. emitNodeInvocations(); emitLeafNodeInvocations(); // Postmatter emitUndefs(); } void TypeNodeEmitter::emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName, StringRef args) { Out << "#ifndef " << macroName << "\n"; Out << "# define " << macroName << args << " " << fallbackMacroName << args << "\n"; Out << "#endif\n"; addMacroToUndef(macroName); } void TypeNodeEmitter::emitNodeInvocations() { TypeNode lastType; visitASTNodeHierarchy(Records, [&](TypeNode type, TypeNode base) { // If this is the Type node itself, skip it; it can't be handled // uniformly by metaprograms because it doesn't have a base. if (!base) return; // Figure out which macro to use. StringRef macroName; auto setMacroName = [&](StringRef newName) { if (!macroName.empty()) PrintFatalError(type.getLoc(), Twine("conflict when computing macro name for " "Type node: trying to use both \"") + macroName + "\" and \"" + newName + "\""); macroName = newName; }; if (type.isSubClassOf(AlwaysDependentClassName)) setMacroName(DependentTypeMacroName); if (type.isSubClassOf(NeverCanonicalClassName)) setMacroName(NonCanonicalTypeMacroName); if (type.isSubClassOf(NeverCanonicalUnlessDependentClassName)) setMacroName(NonCanonicalUnlessDependentTypeMacroName); if (type.isAbstract()) setMacroName(AbstractTypeMacroName); if (macroName.empty()) macroName = TypeMacroName; // Generate the invocation line. Out << macroName << "(" << type.getId() << ", " << base.getClassName() << ")\n"; lastType = type; }); emitLastNodeInvocation(lastType); } void TypeNodeEmitter::emitLastNodeInvocation(TypeNode type) { // We check that this is non-empty earlier. Out << "#ifdef " LastTypeMacroName "\n" LastTypeMacroName "(" << type.getId() << ")\n" "#undef " LastTypeMacroName "\n" "#endif\n"; } void TypeNodeEmitter::emitLeafNodeInvocations() { Out << "#ifdef " LeafTypeMacroName "\n"; for (TypeNode type : Types) { if (!type.isSubClassOf(LeafTypeClassName)) continue; Out << LeafTypeMacroName "(" << type.getId() << ")\n"; } Out << "#undef " LeafTypeMacroName "\n" "#endif\n"; } void TypeNodeEmitter::addMacroToUndef(StringRef macroName) { MacrosToUndef.push_back(macroName); } void TypeNodeEmitter::emitUndefs() { for (auto ¯oName : MacrosToUndef) { Out << "#undef " << macroName << "\n"; } } void clang::EmitClangTypeNodes(RecordKeeper &records, raw_ostream &out) { TypeNodeEmitter(records, out).emit(); }