blob: c9986c8fa496b6fa2d18e275c244ae4970a583de [file] [log] [blame]
//=== 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 <set>
#include <string>
#include <vector>
#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<Record*> Types;
std::vector<StringRef> 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 &macroName : MacrosToUndef) {
Out << "#undef " << macroName << "\n";
}
}
void clang::EmitClangTypeNodes(RecordKeeper &records, raw_ostream &out) {
TypeNodeEmitter(records, out).emit();
}