reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
//=== 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 "ClangASTEmitters.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 <set>
#include <string>
#include <vector>

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"

#define TypeClassName "Type"

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(TypeNodeClassName)) {
	}

	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 without the Type suffix.
		StringRef id = getIdForType(type);

		// If this is the Type node itself, skip it.
		if (id.empty()) continue;

		// 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 (auto base = type->getValueAsOptionalDef(BaseFieldName))
			baseName = base->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();
}