//=== 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 "llvm/ADT/StringRef.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include #include #include #include "TableGenBackends.h" using namespace llvm; // 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" // These are spellings in the tblgen file. // (Type is also used for the spelling of the AST class.) #define TypeClassName "Type" #define DerivedTypeClassName "DerivedType" #define AlwaysDependentClassName "AlwaysDependent" #define NeverCanonicalClassName "NeverCanonical" #define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent" #define LeafTypeClassName "LeafType" #define AbstractFieldName "Abstract" #define BaseFieldName "Base" static StringRef getIdForType(Record *type) { // The record name is expected to be the full C++ class name, // including "Type". Check for that and strip it off. auto fullName = type->getName(); if (!fullName.endswith("Type")) PrintFatalError(type->getLoc(), "name of Type node doesn't end in Type"); return fullName.drop_back(4); } 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("Type")) { } void emit(); private: void emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName, StringRef args); void emitNodeInvocations(); void emitLastNodeInvocation(); 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(); emitLastNodeInvocation(); 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() { for (auto type : Types) { // The name with the Type suffix. StringRef id = getIdForType(type); // 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->getValueAsBit(AbstractFieldName)) setMacroName(AbstractTypeMacroName); if (macroName.empty()) macroName = TypeMacroName; // Compute the base class. StringRef baseName = TypeClassName; if (type->isSubClassOf(DerivedTypeClassName)) baseName = type->getValueAsDef(BaseFieldName)->getName(); // Generate the invocation line. Out << macroName << "(" << id << ", " << baseName << ")\n"; } } void TypeNodeEmitter::emitLastNodeInvocation() { // We check that this is non-empty earlier. Out << "#ifdef " LastTypeMacroName "\n" LastTypeMacroName "(" << getIdForType(Types.back()) << ")\n" "#undef " LastTypeMacroName "\n" "#endif\n"; } void TypeNodeEmitter::emitLeafNodeInvocations() { Out << "#ifdef " LeafTypeMacroName "\n"; for (auto type : Types) { if (!type->isSubClassOf(LeafTypeClassName)) continue; Out << LeafTypeMacroName "(" << getIdForType(type) << ")\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(); }