335 changes: 335 additions & 0 deletions clang/include/clang/AST/AbstractBasicWriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
//==--- AbstractBasicWriter.h - Abstract basic value serialization --------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef CLANG_AST_ABSTRACTBASICWRITER_H
#define CLANG_AST_ABSTRACTBASICWRITER_H

#include "clang/AST/DeclTemplate.h"

namespace clang {
namespace serialization {

template <class T>
inline llvm::Optional<T> makeOptionalFromNullable(const T &value) {
return (value.isNull()
? llvm::Optional<T>()
: llvm::Optional<T>(value));
}

template <class T>
inline llvm::Optional<T*> makeOptionalFromPointer(T *value) {
return (value ? llvm::Optional<T*>(value) : llvm::Optional<T*>());
}

// PropertyWriter is a class concept that requires the following method:
// BasicWriter find(llvm::StringRef propertyName);
// where BasicWriter is some class conforming to the BasicWriter concept.
// An abstract AST-node writer is created with a PropertyWriter and
// performs a sequence of calls like so:
// propertyWriter.find(propertyName).write##TypeName(value)
// to write the properties of the node it is serializing.

// BasicWriter is a class concept that requires methods like:
// void write##TypeName(ValueType value);
// where TypeName is the name of a PropertyType node from PropertiesBase.td
// and ValueType is the corresponding C++ type name.

// WriteDispatcher is a template which does type-based forwarding to one
// of the write methods of the BasicWriter passed in:
//
// template <class ValueType>
// struct WriteDispatcher {
// template <class BasicWriter>
// static void write(BasicWriter &W, ValueType value);
// };

// BasicWriterBase provides convenience implementations of the write
// methods for EnumPropertyType and SubclassPropertyType types that just
// defer to the "underlying" implementations (for UInt32 and the base class,
// respectively).
//
// template <class Impl>
// class BasicWriterBase {
// protected:
// Impl &asImpl();
// public:
// ...
// };

// The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
#include "clang/AST/AbstractBasicWriter.inc"

/// DataStreamBasicWriter provides convenience implementations for many
/// BasicWriter methods based on the assumption that the
/// ultimate writer implementation is based on a variable-length stream
/// of unstructured data (like Clang's module files). It is designed
/// to pair with DataStreamBasicReader.
///
/// This class can also act as a PropertyWriter, implementing find("...")
/// by simply forwarding to itself.
///
/// Unimplemented methods:
/// writeBool
/// writeUInt32
/// writeUInt64
/// writeIdentifier
/// writeSelector
/// writeSourceLocation
/// writeQualType
/// writeStmtRef
/// writeDeclRef
template <class Impl>
class DataStreamBasicWriter : public BasicWriterBase<Impl> {
protected:
using BasicWriterBase<Impl>::asImpl;

public:
/// Implement property-find by ignoring it. We rely on properties being
/// serialized and deserialized in a reliable order instead.
Impl &find(const char *propertyName) {
return asImpl();
}

template <class T>
void writeArray(llvm::ArrayRef<T> array) {
asImpl().writeUInt32(array.size());
for (const T &elt : array) {
WriteDispatcher<T>::write(asImpl(), elt);
}
}

template <class T>
void writeOptional(llvm::Optional<T> value) {
WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
}

void writeAPSInt(const llvm::APSInt &value) {
asImpl().writeBool(value.isUnsigned());
asImpl().writeAPInt(value);
}

void writeAPInt(const llvm::APInt &value) {
asImpl().writeUInt32(value.getBitWidth());
const uint64_t *words = value.getRawData();
for (size_t i = 0, e = value.getNumWords(); i != e; ++i)
asImpl().writeUInt64(words[i]);
}

void writeQualifiers(Qualifiers value) {
static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t),
"update this if the value size changes");
asImpl().writeUInt32(value.getAsOpaqueValue());
}

void writeExceptionSpecInfo(
const FunctionProtoType::ExceptionSpecInfo &esi) {
asImpl().writeUInt32(uint32_t(esi.Type));
if (esi.Type == EST_Dynamic) {
asImpl().writeArray(esi.Exceptions);
} else if (isComputedNoexcept(esi.Type)) {
asImpl().writeExprRef(esi.NoexceptExpr);
} else if (esi.Type == EST_Uninstantiated) {
asImpl().writeDeclRef(esi.SourceDecl);
asImpl().writeDeclRef(esi.SourceTemplate);
} else if (esi.Type == EST_Unevaluated) {
asImpl().writeDeclRef(esi.SourceDecl);
}
}

void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) {
static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t),
"opaque value doesn't fit into uint32_t");
asImpl().writeUInt32(epi.getOpaqueValue());
}

void writeDeclarationName(DeclarationName name) {
asImpl().writeDeclarationNameKind(name.getNameKind());
switch (name.getNameKind()) {
case DeclarationName::Identifier:
asImpl().writeIdentifier(name.getAsIdentifierInfo());
return;

case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
asImpl().writeSelector(name.getObjCSelector());
return;

case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
asImpl().writeQualType(name.getCXXNameType());
return;

case DeclarationName::CXXDeductionGuideName:
asImpl().writeDeclRef(name.getCXXDeductionGuideTemplate());
return;

case DeclarationName::CXXOperatorName:
asImpl().writeOverloadedOperatorKind(name.getCXXOverloadedOperator());
return;

case DeclarationName::CXXLiteralOperatorName:
asImpl().writeIdentifier(name.getCXXLiteralIdentifier());
return;

case DeclarationName::CXXUsingDirective:
// No extra data to emit
return;
}
llvm_unreachable("bad name kind");
}

void writeTemplateName(TemplateName name) {
asImpl().writeTemplateNameKind(name.getKind());
switch (name.getKind()) {
case TemplateName::Template:
asImpl().writeDeclRef(name.getAsTemplateDecl());
return;

case TemplateName::OverloadedTemplate: {
OverloadedTemplateStorage *overload = name.getAsOverloadedTemplate();
asImpl().writeArray(llvm::makeArrayRef(overload->begin(),
overload->end()));
return;
}

case TemplateName::AssumedTemplate: {
AssumedTemplateStorage *assumed = name.getAsAssumedTemplateName();
asImpl().writeDeclarationName(assumed->getDeclName());
return;
}

case TemplateName::QualifiedTemplate: {
QualifiedTemplateName *qual = name.getAsQualifiedTemplateName();
asImpl().writeNestedNameSpecifier(qual->getQualifier());
asImpl().writeBool(qual->hasTemplateKeyword());
asImpl().writeDeclRef(qual->getTemplateDecl());
return;
}

case TemplateName::DependentTemplate: {
DependentTemplateName *dep = name.getAsDependentTemplateName();
asImpl().writeNestedNameSpecifier(dep->getQualifier());
asImpl().writeBool(dep->isIdentifier());
if (dep->isIdentifier())
asImpl().writeIdentifier(dep->getIdentifier());
else
asImpl().writeOverloadedOperatorKind(dep->getOperator());
return;
}

case TemplateName::SubstTemplateTemplateParm: {
auto subst = name.getAsSubstTemplateTemplateParm();
asImpl().writeDeclRef(subst->getParameter());
asImpl().writeTemplateName(subst->getReplacement());
return;
}

case TemplateName::SubstTemplateTemplateParmPack: {
auto substPack = name.getAsSubstTemplateTemplateParmPack();
asImpl().writeDeclRef(substPack->getParameterPack());
asImpl().writeTemplateArgument(substPack->getArgumentPack());
return;
}
}
llvm_unreachable("bad template name kind");
}

void writeTemplateArgument(const TemplateArgument &arg) {
asImpl().writeTemplateArgumentKind(arg.getKind());
switch (arg.getKind()) {
case TemplateArgument::Null:
return;
case TemplateArgument::Type:
asImpl().writeQualType(arg.getAsType());
return;
case TemplateArgument::Declaration:
asImpl().writeValueDeclRef(arg.getAsDecl());
asImpl().writeQualType(arg.getParamTypeForDecl());
return;
case TemplateArgument::NullPtr:
asImpl().writeQualType(arg.getNullPtrType());
return;
case TemplateArgument::Integral:
asImpl().writeAPSInt(arg.getAsIntegral());
asImpl().writeQualType(arg.getIntegralType());
return;
case TemplateArgument::Template:
asImpl().writeTemplateName(arg.getAsTemplateOrTemplatePattern());
return;
case TemplateArgument::TemplateExpansion: {
asImpl().writeTemplateName(arg.getAsTemplateOrTemplatePattern());
// Convert Optional<unsigned> to Optional<uint32>, just in case.
Optional<unsigned> numExpansions = arg.getNumTemplateExpansions();
Optional<uint32_t> numExpansions32;
if (numExpansions) numExpansions32 = *numExpansions;
asImpl().template writeOptional<uint32_t>(numExpansions32);
return;
}
case TemplateArgument::Expression:
asImpl().writeExprRef(arg.getAsExpr());
return;
case TemplateArgument::Pack:
asImpl().template writeArray<TemplateArgument>(arg.pack_elements());
return;
}
llvm_unreachable("bad template argument kind");
}

void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
// Nested name specifiers usually aren't too long. I think that 8 would
// typically accommodate the vast majority.
SmallVector<NestedNameSpecifier *, 8> nestedNames;

// Push each of the NNS's onto a stack for serialization in reverse order.
while (NNS) {
nestedNames.push_back(NNS);
NNS = NNS->getPrefix();
}

asImpl().writeUInt32(nestedNames.size());
while (!nestedNames.empty()) {
NNS = nestedNames.pop_back_val();
NestedNameSpecifier::SpecifierKind kind = NNS->getKind();
asImpl().writeNestedNameSpecifierKind(kind);
switch (kind) {
case NestedNameSpecifier::Identifier:
asImpl().writeIdentifier(NNS->getAsIdentifier());
continue;

case NestedNameSpecifier::Namespace:
asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
continue;

case NestedNameSpecifier::NamespaceAlias:
asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
continue;

case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
asImpl().writeQualType(QualType(NNS->getAsType(), 0));
continue;

case NestedNameSpecifier::Global:
// Don't need to write an associated value.
continue;

case NestedNameSpecifier::Super:
asImpl().writeDeclRef(NNS->getAsRecordDecl());
continue;
}
llvm_unreachable("bad nested name specifier kind");
}
}
};

} // end namespace serialization
} // end namespace clang

#endif
31 changes: 31 additions & 0 deletions clang/include/clang/AST/AbstractTypeReader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//==--- AbstractTypeReader.h - Abstract deserialization for types ---------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef CLANG_AST_ABSTRACTTYPEREADER_H
#define CLANG_AST_ABSTRACTTYPEREADER_H

#include "clang/AST/Type.h"
#include "clang/AST/AbstractBasicReader.h"

namespace clang {
namespace serialization {

// template <class PropertyReader>
// class AbstractTypeReader {
// public:
// AbstractTypeReader(PropertyReader &W);
// QualType read(Type::TypeClass kind);
// };
//
// The actual class is auto-generated; see ClangASTPropertiesEmitter.cpp.
#include "clang/AST/AbstractTypeReader.inc"

} // end namespace serialization
} // end namespace clang

#endif
32 changes: 32 additions & 0 deletions clang/include/clang/AST/AbstractTypeWriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//==--- AbstractTypeWriter.h - Abstract serialization for types -----------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef CLANG_AST_ABSTRACTTYPEWRITER_H
#define CLANG_AST_ABSTRACTTYPEWRITER_H

#include "clang/AST/Type.h"
#include "clang/AST/AbstractBasicWriter.h"
#include "clang/AST/DeclObjC.h"

namespace clang {
namespace serialization {

// template <class PropertyWriter>
// class AbstractTypeWriter {
// public:
// AbstractTypeWriter(PropertyWriter &W);
// void write(QualType type);
// };
//
// The actual class is auto-generated; see ClangASTPropertiesEmitter.cpp.
#include "clang/AST/AbstractTypeWriter.inc"

} // end namespace serialization
} // end namespace clang

#endif
16 changes: 16 additions & 0 deletions clang/include/clang/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ clang_tablegen(TypeNodes.inc -gen-clang-type-nodes
SOURCE ../Basic/TypeNodes.td
TARGET ClangTypeNodes)

clang_tablegen(AbstractBasicReader.inc -gen-clang-basic-reader
SOURCE PropertiesBase.td
TARGET ClangAbstractBasicReader)

clang_tablegen(AbstractBasicWriter.inc -gen-clang-basic-writer
SOURCE PropertiesBase.td
TARGET ClangAbstractBasicWriter)

clang_tablegen(AbstractTypeReader.inc -gen-clang-type-reader
SOURCE TypeProperties.td
TARGET ClangAbstractTypeReader)

clang_tablegen(AbstractTypeWriter.inc -gen-clang-type-writer
SOURCE TypeProperties.td
TARGET ClangAbstractTypeWriter)

clang_tablegen(CommentNodes.inc -gen-clang-comment-nodes
SOURCE ../Basic/CommentNodes.td
TARGET ClangCommentNodes)
Expand Down
179 changes: 179 additions & 0 deletions clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//==--- PropertiesBase.td - Baseline definitions for AST properties -------===//
//
// 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
//
//===----------------------------------------------------------------------===//

class ASTNode;

/// The type of the property.
class PropertyType<string typeName = ""> {
/// The C++ type name for the type.
string CXXName = !if(!ne(typeName, ""), typeName, NAME);

/// Whether the C++ type should generally be passed around by reference.
bit PassByReference = 0;

/// Whether `const` should be prepended to the type when writing.
bit ConstWhenWriting = 0;

/// Given a value of type Optional<CXXName> bound as 'value', yield a
/// CXXName that can be serialized into a DataStreamTypeWriter.
string PackOptional = "";

/// Given a value of type CXXName bound as 'value' that was deserialized
/// by a DataStreamTypeReader, yield an Optional<CXXName>.
string UnpackOptional = "";

/// A list of types for which buffeers must be passed to the read
/// operations.
list<PropertyType> BufferElementTypes = [];
}

/// Property types that correspond to specific C++ enums.
class EnumPropertyType<string typeName = ""> : PropertyType<typeName> {}

/// Property types that correspond to a specific C++ class.
/// Supports optional values by using the null representation.
class RefPropertyType<string className> : PropertyType<className # "*"> {
let PackOptional =
"value ? *value : nullptr";
let UnpackOptional =
"value ? llvm::Optional<" # CXXName # ">(value) : llvm::None";
}

/// Property types that correspond to a specific subclass of another type.
class SubclassPropertyType<string className, PropertyType base>
: RefPropertyType<className> {
PropertyType Base = base;
string SubclassName = className;
let ConstWhenWriting = base.ConstWhenWriting;
}

/// Property types that support optional values by using their
/// default value.
class DefaultValuePropertyType<string typeName = ""> : PropertyType<typeName> {
let PackOptional =
"value ? *value : " # CXXName # "()";
let UnpackOptional =
"value.isNull() ? llvm::None : llvm::Optional<" # CXXName # ">(value)";
}

/// Property types that correspond to integer types and support optional
/// values by shifting the value over by 1.
class CountPropertyType<string typeName = ""> : PropertyType<typeName> {
let PackOptional =
"value ? *value + 1 : 0";
let UnpackOptional =
"value ? llvm::Optional<" # CXXName # ">(value - 1) : llvm::None";
}

def APInt : PropertyType<"llvm::APInt"> { let PassByReference = 1; }
def APSInt : PropertyType<"llvm::APSInt"> { let PassByReference = 1; }
def ArraySizeModifier : EnumPropertyType<"ArrayType::ArraySizeModifier">;
def AttrKind : EnumPropertyType<"attr::Kind">;
def AutoTypeKeyword : EnumPropertyType;
def Bool : PropertyType<"bool">;
def BuiltinTypeKind : EnumPropertyType<"BuiltinType::Kind">;
def CallingConv : EnumPropertyType;
def DeclarationName : PropertyType;
def DeclarationNameKind : EnumPropertyType<"DeclarationName::NameKind">;
def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; }
def CXXRecordDeclRef :
SubclassPropertyType<"CXXRecordDecl", DeclRef>;
def FunctionDeclRef :
SubclassPropertyType<"FunctionDecl", DeclRef>;
def NamedDeclRef :
SubclassPropertyType<"NamedDecl", DeclRef>;
def NamespaceDeclRef :
SubclassPropertyType<"NamespaceDecl", DeclRef>;
def NamespaceAliasDeclRef :
SubclassPropertyType<"NamespaceAliasDecl", DeclRef>;
def ObjCProtocolDeclRef :
SubclassPropertyType<"ObjCProtocolDecl", DeclRef>;
def ObjCTypeParamDeclRef :
SubclassPropertyType<"ObjCTypeParamDecl", DeclRef>;
def TagDeclRef :
SubclassPropertyType<"TagDecl", DeclRef>;
def TemplateDeclRef :
SubclassPropertyType<"TemplateDecl", DeclRef>;
def TemplateTypeParmDeclRef :
SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>;
def TemplateTemplateParmDeclRef :
SubclassPropertyType<"TemplateTemplateParmDecl", DeclRef>;
def ValueDeclRef :
SubclassPropertyType<"ValueDecl", DeclRef>;
def ElaboratedTypeKeyword : EnumPropertyType;
def ExtParameterInfo : PropertyType<"FunctionProtoType::ExtParameterInfo">;
def Identifier : PropertyType<"IdentifierInfo*">;
def NestedNameSpecifier : PropertyType<"NestedNameSpecifier *">;
def NestedNameSpecifierKind :
EnumPropertyType<"NestedNameSpecifier::SpecifierKind">;
def OverloadedOperatorKind : EnumPropertyType;
def Qualifiers : PropertyType;
def QualType : DefaultValuePropertyType;
def RefQualifierKind : EnumPropertyType;
def Selector : PropertyType;
def SourceLocation : PropertyType;
def StmtRef : RefPropertyType<"Stmt"> { let ConstWhenWriting = 1; }
def ExprRef : SubclassPropertyType<"Expr", StmtRef>;
def TemplateArgument : PropertyType;
def TemplateArgumentKind : EnumPropertyType<"TemplateArgument::ArgKind">;
def TemplateName : DefaultValuePropertyType;
def TemplateNameKind : EnumPropertyType<"TemplateName::NameKind">;
def UInt32 : CountPropertyType<"uint32_t">;
def UInt64 : CountPropertyType<"uint64_t">;
def UnaryTypeTransformKind : EnumPropertyType<"UnaryTransformType::UTTKind">;
def VectorKind : EnumPropertyType<"VectorType::VectorKind">;

def ExceptionSpecInfo : PropertyType<"FunctionProtoType::ExceptionSpecInfo"> {
let BufferElementTypes = [ QualType ];
}

/// Arrays. The corresponding C++ type is ArrayRef of the corresponding
/// C++ type of the element.
class Array<PropertyType element> : PropertyType {
PropertyType Element = element;
let BufferElementTypes = [ element ];
}

/// llvm::Optional<T>. The corresponding C++ type is generally just the
/// corresponding C++ type of the element.
///
/// Optional<Unsigned> may restrict the range of the operand for some
/// serialization clients.
class Optional<PropertyType element> : PropertyType {
PropertyType Element = element;
let PassByReference = element.PassByReference;
}

/// A property of an AST node.
class Property<string name, PropertyType type> {
ASTNode Class;
string Name = name;
PropertyType Type = type;

/// A function for reading the property, expressed in terms of a variable
/// "node".
code Read;
}

/// A rule for creating objects of this type.
class Creator<code create> {
ASTNode Class;

/// A function for creating values of this kind, expressed in terms of a
/// variable `ctx` of type `ASTContext &`. Must also refer to all of the
/// properties by name.
code Create = create;
}

/// A rule which overrides some of the normal rules.
class Override {
ASTNode Class;

/// Properties from base classes that should be ignored.
list<string> IgnoredProperties = [];
}
39 changes: 28 additions & 11 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ enum {
TypeAlignment = 1 << TypeAlignmentInBits
};

namespace serialization {
template <class T> class AbstractTypeReader;
template <class T> class AbstractTypeWriter;
}

} // namespace clang

namespace llvm {
Expand Down Expand Up @@ -1847,6 +1852,8 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
public:
friend class ASTReader;
friend class ASTWriter;
template <class T> friend class serialization::AbstractTypeReader;
template <class T> friend class serialization::AbstractTypeWriter;

Type(const Type &) = delete;
Type(Type &&) = delete;
Expand Down Expand Up @@ -3956,19 +3963,9 @@ class FunctionProtoType final
EPI.Variadic = isVariadic();
EPI.EllipsisLoc = getEllipsisLoc();
EPI.HasTrailingReturn = hasTrailingReturn();
EPI.ExceptionSpec.Type = getExceptionSpecType();
EPI.ExceptionSpec = getExceptionSpecInfo();
EPI.TypeQuals = getMethodQuals();
EPI.RefQualifier = getRefQualifier();
if (EPI.ExceptionSpec.Type == EST_Dynamic) {
EPI.ExceptionSpec.Exceptions = exceptions();
} else if (isComputedNoexcept(EPI.ExceptionSpec.Type)) {
EPI.ExceptionSpec.NoexceptExpr = getNoexceptExpr();
} else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) {
EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl();
EPI.ExceptionSpec.SourceTemplate = getExceptionSpecTemplate();
} else if (EPI.ExceptionSpec.Type == EST_Unevaluated) {
EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl();
}
EPI.ExtParameterInfos = getExtParameterInfosOrNull();
return EPI;
}
Expand Down Expand Up @@ -3999,6 +3996,23 @@ class FunctionProtoType final
/// spec.
bool hasInstantiationDependentExceptionSpec() const;

/// Return all the available information about this type's exception spec.
ExceptionSpecInfo getExceptionSpecInfo() const {
ExceptionSpecInfo Result;
Result.Type = getExceptionSpecType();
if (Result.Type == EST_Dynamic) {
Result.Exceptions = exceptions();
} else if (isComputedNoexcept(Result.Type)) {
Result.NoexceptExpr = getNoexceptExpr();
} else if (Result.Type == EST_Uninstantiated) {
Result.SourceDecl = getExceptionSpecDecl();
Result.SourceTemplate = getExceptionSpecTemplate();
} else if (Result.Type == EST_Unevaluated) {
Result.SourceDecl = getExceptionSpecDecl();
}
return Result;
}

/// Return the number of types in the exception specification.
unsigned getNumExceptions() const {
return getExceptionSpecType() == EST_Dynamic
Expand Down Expand Up @@ -4441,6 +4455,7 @@ class DependentUnaryTransformType : public UnaryTransformType,

class TagType : public Type {
friend class ASTReader;
template <class T> friend class serialization::AbstractTypeReader;

/// Stores the TagDecl associated with this type. The decl may point to any
/// TagDecl that declares the entity.
Expand Down Expand Up @@ -5078,6 +5093,7 @@ class InjectedClassNameType : public Type {
friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not
// currently suitable for AST reading, too much
// interdependencies.
template <class T> friend class serialization::AbstractTypeReader;

CXXRecordDecl *Decl;

Expand Down Expand Up @@ -5836,6 +5852,7 @@ class ObjCInterfaceType : public ObjCObjectType {
friend class ASTContext; // ASTContext creates these.
friend class ASTReader;
friend class ObjCInterfaceDecl;
template <class T> friend class serialization::AbstractTypeReader;

mutable ObjCInterfaceDecl *Decl;

Expand Down
812 changes: 812 additions & 0 deletions clang/include/clang/AST/TypeProperties.td

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion clang/include/clang/Basic/DeclNodes.td
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
class ASTNode;
class AttrSubject;

class DeclNode<DeclNode base, string diagSpelling = "", bit abstract = 0>
: AttrSubject {
: ASTNode, AttrSubject {
DeclNode Base = base;
bit Abstract = abstract;
string DiagSpelling = diagSpelling;
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/StmtNodes.td
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class ASTNode;
class AttrSubject;

class StmtNode<StmtNode base, bit abstract = 0> : AttrSubject {
class StmtNode<StmtNode base, bit abstract = 0> : ASTNode, AttrSubject {
StmtNode Base = base;
bit Abstract = abstract;
}
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/TypeNodes.td
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class TypeNode<TypeNode base, bit abstract = 0> {
class ASTNode;

class TypeNode<TypeNode base, bit abstract = 0> : ASTNode {
TypeNode Base = base;
bit Abstract = abstract;
}
Expand Down
147 changes: 5 additions & 142 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1040,149 +1040,12 @@ namespace serialization {
/// constant describes a record for a specific type class in the
/// AST. Note that DeclCode values share this code space.
enum TypeCode {
/// An ExtQualType record.
TYPE_EXT_QUAL = 1,

/// A ComplexType record.
TYPE_COMPLEX = 3,

/// A PointerType record.
TYPE_POINTER = 4,

/// A BlockPointerType record.
TYPE_BLOCK_POINTER = 5,

/// An LValueReferenceType record.
TYPE_LVALUE_REFERENCE = 6,

/// An RValueReferenceType record.
TYPE_RVALUE_REFERENCE = 7,

/// A MemberPointerType record.
TYPE_MEMBER_POINTER = 8,

/// A ConstantArrayType record.
TYPE_CONSTANT_ARRAY = 9,

/// An IncompleteArrayType record.
TYPE_INCOMPLETE_ARRAY = 10,

/// A VariableArrayType record.
TYPE_VARIABLE_ARRAY = 11,

/// A VectorType record.
TYPE_VECTOR = 12,

/// An ExtVectorType record.
TYPE_EXT_VECTOR = 13,

/// A FunctionNoProtoType record.
TYPE_FUNCTION_NO_PROTO = 14,

/// A FunctionProtoType record.
TYPE_FUNCTION_PROTO = 15,

/// A TypedefType record.
TYPE_TYPEDEF = 16,

/// A TypeOfExprType record.
TYPE_TYPEOF_EXPR = 17,

/// A TypeOfType record.
TYPE_TYPEOF = 18,

/// A RecordType record.
TYPE_RECORD = 19,

/// An EnumType record.
TYPE_ENUM = 20,

/// An ObjCInterfaceType record.
TYPE_OBJC_INTERFACE = 21,

/// An ObjCObjectPointerType record.
TYPE_OBJC_OBJECT_POINTER = 22,

/// a DecltypeType record.
TYPE_DECLTYPE = 23,

/// An ElaboratedType record.
TYPE_ELABORATED = 24,

/// A SubstTemplateTypeParmType record.
TYPE_SUBST_TEMPLATE_TYPE_PARM = 25,
#define TYPE_BIT_CODE(CLASS_ID, CODE_ID, CODE_VALUE) \
TYPE_##CODE_ID = CODE_VALUE,
#include "clang/Serialization/TypeBitCodes.def"

/// An UnresolvedUsingType record.
TYPE_UNRESOLVED_USING = 26,

/// An InjectedClassNameType record.
TYPE_INJECTED_CLASS_NAME = 27,

/// An ObjCObjectType record.
TYPE_OBJC_OBJECT = 28,

/// An TemplateTypeParmType record.
TYPE_TEMPLATE_TYPE_PARM = 29,

/// An TemplateSpecializationType record.
TYPE_TEMPLATE_SPECIALIZATION = 30,

/// A DependentNameType record.
TYPE_DEPENDENT_NAME = 31,

/// A DependentTemplateSpecializationType record.
TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION = 32,

/// A DependentSizedArrayType record.
TYPE_DEPENDENT_SIZED_ARRAY = 33,

/// A ParenType record.
TYPE_PAREN = 34,

/// A PackExpansionType record.
TYPE_PACK_EXPANSION = 35,

/// An AttributedType record.
TYPE_ATTRIBUTED = 36,

/// A SubstTemplateTypeParmPackType record.
TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37,

/// A AutoType record.
TYPE_AUTO = 38,

/// A UnaryTransformType record.
TYPE_UNARY_TRANSFORM = 39,

/// An AtomicType record.
TYPE_ATOMIC = 40,

/// A DecayedType record.
TYPE_DECAYED = 41,

/// An AdjustedType record.
TYPE_ADJUSTED = 42,

/// A PipeType record.
TYPE_PIPE = 43,

/// An ObjCTypeParamType record.
TYPE_OBJC_TYPE_PARAM = 44,

/// A DeducedTemplateSpecializationType record.
TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45,

/// A DependentSizedExtVectorType record.
TYPE_DEPENDENT_SIZED_EXT_VECTOR = 46,

/// A DependentAddressSpaceType record.
TYPE_DEPENDENT_ADDRESS_SPACE = 47,

/// A dependentSizedVectorType record.
TYPE_DEPENDENT_SIZED_VECTOR = 48,

/// A type defined in a macro.
TYPE_MACRO_QUALIFIED = 49
/// An ExtQualType record.
TYPE_EXT_QUAL = 1
};

/// The type IDs for special types constructed by semantic
Expand Down
257 changes: 73 additions & 184 deletions clang/include/clang/Serialization/ASTReader.h

Large diffs are not rendered by default.

58 changes: 51 additions & 7 deletions clang/include/clang/Serialization/ASTWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_SERIALIZATION_ASTWRITER_H
#define LLVM_CLANG_SERIALIZATION_ASTWRITER_H

#include "clang/AST/AbstractBasicWriter.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclarationName.h"
Expand Down Expand Up @@ -745,7 +746,8 @@ class ASTWriter : public ASTDeserializationListener,
};

/// An object for streaming information to a record.
class ASTRecordWriter {
class ASTRecordWriter
: public serialization::DataStreamBasicWriter<ASTRecordWriter> {
ASTWriter *Writer;
ASTWriter::RecordDataImpl *Record;

Expand Down Expand Up @@ -839,6 +841,9 @@ class ASTRecordWriter {
void AddStmt(Stmt *S) {
StmtsToEmit.push_back(S);
}
void writeStmtRef(const Stmt *S) {
AddStmt(const_cast<Stmt*>(S));
}

/// Add a definition for the given function to the queue of statements
/// to emit.
Expand All @@ -848,17 +853,36 @@ class ASTRecordWriter {
void AddSourceLocation(SourceLocation Loc) {
return Writer->AddSourceLocation(Loc, *Record);
}
void writeSourceLocation(SourceLocation Loc) {
AddSourceLocation(Loc);
}

/// Emit a source range.
void AddSourceRange(SourceRange Range) {
return Writer->AddSourceRange(Range, *Record);
}

void writeBool(bool Value) {
Record->push_back(Value);
}

void writeUInt32(uint32_t Value) {
Record->push_back(Value);
}

void writeUInt64(uint64_t Value) {
Record->push_back(Value);
}

/// Emit an integral value.
void AddAPInt(const llvm::APInt &Value);
void AddAPInt(const llvm::APInt &Value) {
writeAPInt(Value);
}

/// Emit a signed integral value.
void AddAPSInt(const llvm::APSInt &Value);
void AddAPSInt(const llvm::APSInt &Value) {
writeAPSInt(Value);
}

/// Emit a floating-point value.
void AddAPFloat(const llvm::APFloat &Value);
Expand All @@ -870,9 +894,15 @@ class ASTRecordWriter {
void AddIdentifierRef(const IdentifierInfo *II) {
return Writer->AddIdentifierRef(II, *Record);
}
void writeIdentifier(const IdentifierInfo *II) {
AddIdentifierRef(II);
}

/// Emit a Selector (which is a smart pointer reference).
void AddSelectorRef(Selector S);
void writeSelector(Selector sel) {
AddSelectorRef(sel);
}

/// Emit a CXXTemporary.
void AddCXXTemporary(const CXXTemporary *Temp);
Expand All @@ -887,6 +917,9 @@ class ASTRecordWriter {
void AddTypeRef(QualType T) {
return Writer->AddTypeRef(T, *Record);
}
void writeQualType(QualType T) {
AddTypeRef(T);
}

/// Emits a reference to a declarator info.
void AddTypeSourceInfo(TypeSourceInfo *TInfo);
Expand All @@ -909,9 +942,14 @@ class ASTRecordWriter {
void AddDeclRef(const Decl *D) {
return Writer->AddDeclRef(D, *Record);
}
void writeDeclRef(const Decl *D) {
AddDeclRef(D);
}

/// Emit a declaration name.
void AddDeclarationName(DeclarationName Name);
void AddDeclarationName(DeclarationName Name) {
writeDeclarationName(Name);
}

void AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc,
DeclarationName Name);
Expand All @@ -920,16 +958,22 @@ class ASTRecordWriter {
void AddQualifierInfo(const QualifierInfo &Info);

/// Emit a nested name specifier.
void AddNestedNameSpecifier(NestedNameSpecifier *NNS);
void AddNestedNameSpecifier(NestedNameSpecifier *NNS) {
writeNestedNameSpecifier(NNS);
}

/// Emit a nested name specifier with source-location information.
void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);

/// Emit a template name.
void AddTemplateName(TemplateName Name);
void AddTemplateName(TemplateName Name) {
writeTemplateName(Name);
}

/// Emit a template argument.
void AddTemplateArgument(const TemplateArgument &Arg);
void AddTemplateArgument(const TemplateArgument &Arg) {
writeTemplateArgument(Arg);
}

/// Emit a template parameter list.
void AddTemplateParameterList(const TemplateParameterList *TemplateParams);
Expand Down
62 changes: 62 additions & 0 deletions clang/include/clang/Serialization/TypeBitCodes.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//===--- TypeNodeBitCodes.def - Type to bitcode correspondance --*- 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 file provides an x-macro link between AST Type IDs and
// their stable serialized bit-code record type IDs.
//
//===----------------------------------------------------------------------===//

TYPE_BIT_CODE(Complex, COMPLEX, 3)
TYPE_BIT_CODE(Pointer, POINTER, 4)
TYPE_BIT_CODE(BlockPointer, BLOCK_POINTER, 5)
TYPE_BIT_CODE(LValueReference, LVALUE_REFERENCE, 6)
TYPE_BIT_CODE(RValueReference, RVALUE_REFERENCE, 7)
TYPE_BIT_CODE(MemberPointer, MEMBER_POINTER, 8)
TYPE_BIT_CODE(ConstantArray, CONSTANT_ARRAY, 9)
TYPE_BIT_CODE(IncompleteArray, INCOMPLETE_ARRAY, 10)
TYPE_BIT_CODE(VariableArray, VARIABLE_ARRAY, 11)
TYPE_BIT_CODE(Vector, VECTOR, 12)
TYPE_BIT_CODE(ExtVector, EXT_VECTOR, 13)
TYPE_BIT_CODE(FunctionNoProto, FUNCTION_NO_PROTO, 14)
TYPE_BIT_CODE(FunctionProto, FUNCTION_PROTO, 15)
TYPE_BIT_CODE(Typedef, TYPEDEF, 16)
TYPE_BIT_CODE(TypeOfExpr, TYPEOF_EXPR, 17)
TYPE_BIT_CODE(TypeOf, TYPEOF, 18)
TYPE_BIT_CODE(Record, RECORD, 19)
TYPE_BIT_CODE(Enum, ENUM, 20)
TYPE_BIT_CODE(ObjCInterface, OBJC_INTERFACE, 21)
TYPE_BIT_CODE(ObjCObjectPointer, OBJC_OBJECT_POINTER, 22)
TYPE_BIT_CODE(Decltype, DECLTYPE, 23)
TYPE_BIT_CODE(Elaborated, ELABORATED, 24)
TYPE_BIT_CODE(SubstTemplateTypeParm, SUBST_TEMPLATE_TYPE_PARM, 25)
TYPE_BIT_CODE(UnresolvedUsing, UNRESOLVED_USING, 26)
TYPE_BIT_CODE(InjectedClassName, INJECTED_CLASS_NAME, 27)
TYPE_BIT_CODE(ObjCObject, OBJC_OBJECT, 28)
TYPE_BIT_CODE(TemplateTypeParm, TEMPLATE_TYPE_PARM, 29)
TYPE_BIT_CODE(TemplateSpecialization, TEMPLATE_SPECIALIZATION, 30)
TYPE_BIT_CODE(DependentName, DEPENDENT_NAME, 31)
TYPE_BIT_CODE(DependentTemplateSpecialization, DEPENDENT_TEMPLATE_SPECIALIZATION, 32)
TYPE_BIT_CODE(DependentSizedArray, DEPENDENT_SIZED_ARRAY, 33)
TYPE_BIT_CODE(Paren, PAREN, 34)
TYPE_BIT_CODE(PackExpansion, PACK_EXPANSION, 35)
TYPE_BIT_CODE(Attributed, ATTRIBUTED, 36)
TYPE_BIT_CODE(SubstTemplateTypeParmPack, SUBST_TEMPLATE_TYPE_PARM_PACK, 37)
TYPE_BIT_CODE(Auto, AUTO, 38)
TYPE_BIT_CODE(UnaryTransform, UNARY_TRANSFORM, 39)
TYPE_BIT_CODE(Atomic, ATOMIC, 40)
TYPE_BIT_CODE(Decayed, DECAYED, 41)
TYPE_BIT_CODE(Adjusted, ADJUSTED, 42)
TYPE_BIT_CODE(Pipe, PIPE, 43)
TYPE_BIT_CODE(ObjCTypeParam, OBJC_TYPE_PARAM, 44)
TYPE_BIT_CODE(DeducedTemplateSpecialization, DEDUCED_TEMPLATE_SPECIALIZATION, 45)
TYPE_BIT_CODE(DependentSizedExtVector, DEPENDENT_SIZED_EXT_VECTOR, 46)
TYPE_BIT_CODE(DependentAddressSpace, DEPENDENT_ADDRESS_SPACE, 47)
TYPE_BIT_CODE(DependentVector, DEPENDENT_SIZED_VECTOR, 48)
TYPE_BIT_CODE(MacroQualified, MACRO_QUALIFIED, 49)

#undef TYPE_BIT_CODE
1,310 changes: 247 additions & 1,063 deletions clang/lib/Serialization/ASTReader.cpp

Large diffs are not rendered by default.

479 changes: 233 additions & 246 deletions clang/lib/Serialization/ASTReaderDecl.cpp

Large diffs are not rendered by default.

605 changes: 298 additions & 307 deletions clang/lib/Serialization/ASTReaderStmt.cpp

Large diffs are not rendered by default.

684 changes: 37 additions & 647 deletions clang/lib/Serialization/ASTWriter.cpp

Large diffs are not rendered by default.

132 changes: 132 additions & 0 deletions clang/utils/TableGen/ASTTableGen.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//=== ASTTableGen.cpp - Helper functions for working with AST records -----===//
//
// 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 file defines some helper functions for working with tblegen reocrds
// for the Clang AST: that is, the contents of files such as DeclNodes.td,
// StmtNodes.td, and TypeNodes.td.
//
//===----------------------------------------------------------------------===//

#include "ASTTableGen.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/Error.h"

using namespace llvm;
using namespace clang;
using namespace clang::tblgen;

static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
StringRef nodeName = node->getName();
if (!nodeName.endswith(suffix)) {
PrintFatalError(node->getLoc(),
Twine("name of node doesn't end in ") + suffix);
}
return nodeName.drop_back(suffix.size());
}

// Decl node names don't end in Decl for historical reasons, and it would
// be somewhat annoying to fix now. Conveniently, this means the ID matches
// is exactly the node name, and the class name is simply that plus Decl.
std::string clang::tblgen::DeclNode::getClassName() const {
return (Twine(getName()) + "Decl").str();
}
StringRef clang::tblgen::DeclNode::getId() const {
return getName();
}

// Type nodes are all named ending in Type, just like the corresponding
// C++ class, and the ID just strips this suffix.
StringRef clang::tblgen::TypeNode::getClassName() const {
return getName();
}
StringRef clang::tblgen::TypeNode::getId() const {
return removeExpectedNodeNameSuffix(getRecord(), "Type");
}

// Stmt nodes are named the same as the C++ class, which has no regular
// naming convention (all the non-expression statements end in Stmt,
// and *many* expressions end in Expr, but there are also several
// core expression classes like IntegerLiteral and BinaryOperator with
// no standard suffix). The ID adds "Class" for historical reasons.
StringRef clang::tblgen::StmtNode::getClassName() const {
return getName();
}
std::string clang::tblgen::StmtNode::getId() const {
return (Twine(getName()) + "Class").str();
}

/// Emit a string spelling out the C++ value type.
void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const {
if (!isGenericSpecialization()) {
if (!forRead && isConstWhenWriting())
out << "const ";
out << getCXXTypeName();
} else if (auto elementType = getArrayElementType()) {
out << "llvm::ArrayRef<";
elementType.emitCXXValueTypeName(forRead, out);
out << ">";
} else if (auto valueType = getOptionalElementType()) {
out << "llvm::Optional<";
valueType.emitCXXValueTypeName(forRead, out);
out << ">";
} else {
//PrintFatalError(getLoc(), "unexpected generic property type");
abort();
}
}

// A map from a node to each of its child nodes.
using ChildMap = std::multimap<ASTNode, ASTNode>;

static void visitASTNodeRecursive(ASTNode node, ASTNode base,
const ChildMap &map,
ASTNodeHierarchyVisitor<ASTNode> visit) {
visit(node, base);

auto i = map.lower_bound(node), e = map.upper_bound(node);
for (; i != e; ++i) {
visitASTNodeRecursive(i->second, node, map, visit);
}
}

static void visitHierarchy(RecordKeeper &records,
StringRef nodeClassName,
ASTNodeHierarchyVisitor<ASTNode> visit) {
// Check for the node class, just as a sanity check.
if (!records.getClass(nodeClassName)) {
PrintFatalError(Twine("cannot find definition for node class ")
+ nodeClassName);
}

// Find all the nodes in the hierarchy.
auto nodes = records.getAllDerivedDefinitions(nodeClassName);

// Derive the child map.
ChildMap hierarchy;
ASTNode root;
for (ASTNode node : nodes) {
if (auto base = node.getBase())
hierarchy.insert(std::make_pair(base, node));
else if (root)
PrintFatalError(node.getLoc(),
"multiple root nodes in " + nodeClassName + " hierarchy");
else
root = node;
}
if (!root)
PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy");

// Now visit the map recursively, starting at the root node.
visitASTNodeRecursive(root, ASTNode(), hierarchy, visit);
}

void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records,
StringRef nodeClassName,
ASTNodeHierarchyVisitor<ASTNode> visit) {
visitHierarchy(records, nodeClassName, visit);
}
364 changes: 364 additions & 0 deletions clang/utils/TableGen/ASTTableGen.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,364 @@
//=== ASTTableGen.h - Common definitions for AST node tablegen --*- 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
//
//===----------------------------------------------------------------------===//

#ifndef CLANG_AST_TABLEGEN_H
#define CLANG_AST_TABLEGEN_H

#include "llvm/TableGen/Record.h"
#include "llvm/ADT/STLExtras.h"

// These are spellings in the tblgen files.

// Field names that are fortunately common across the hierarchies.
#define BaseFieldName "Base"
#define AbstractFieldName "Abstract"

// Comment node hierarchy.
#define CommentNodeClassName "CommentNode"

// Decl node hierarchy.
#define DeclNodeClassName "DeclNode"
#define DeclContextNodeClassName "DeclContext"

// Stmt node hierarchy.
#define StmtNodeClassName "StmtNode"

// Type node hierarchy.
#define TypeNodeClassName "TypeNode"
#define AlwaysDependentClassName "AlwaysDependent"
#define NeverCanonicalClassName "NeverCanonical"
#define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent"
#define LeafTypeClassName "LeafType"

// Properties of AST nodes.
#define PropertyClassName "Property"
#define ClassFieldName "Class"
#define NameFieldName "Name"
#define TypeFieldName "Type"
#define ReadFieldName "Read"

// Types of properties.
#define PropertyTypeClassName "PropertyType"
#define CXXTypeNameFieldName "CXXName"
#define PassByReferenceFieldName "PassByReference"
#define ConstWhenWritingFieldName "ConstWhenWriting"
#define PackOptionalCodeFieldName "PackOptional"
#define UnpackOptionalCodeFieldName "UnpackOptional"
#define BufferElementTypesFieldName "BufferElementTypes"
#define ArrayTypeClassName "Array"
#define ArrayElementTypeFieldName "Element"
#define OptionalTypeClassName "Optional"
#define OptionalElementTypeFieldName "Element"
#define SubclassPropertyTypeClassName "SubclassPropertyType"
#define SubclassBaseTypeFieldName "Base"
#define SubclassClassNameFieldName "SubclassName"
#define EnumPropertyTypeClassName "EnumPropertyType"

// Creation rules.
#define CreationRuleClassName "Creator"
#define CreateFieldName "Create"

// Override rules.
#define OverrideRuleClassName "Override"
#define IgnoredPropertiesFieldName "IgnoredProperties"

namespace clang {
namespace tblgen {

class WrappedRecord {
llvm::Record *Record;

protected:
WrappedRecord(llvm::Record *record = nullptr) : Record(record) {}

llvm::Record *get() const {
assert(Record && "accessing null record");
return Record;
}

public:
llvm::Record *getRecord() const { return Record; }

explicit operator bool() const { return Record != nullptr; }

llvm::ArrayRef<llvm::SMLoc> getLoc() const {
return get()->getLoc();
}

/// Does the node inherit from the given TableGen class?
bool isSubClassOf(llvm::StringRef className) const {
return get()->isSubClassOf(className);
}
};

/// An (optional) reference to a TableGen node representing a class
/// in one of Clang's AST hierarchies.
class ASTNode : public WrappedRecord {
public:
ASTNode(llvm::Record *record = nullptr) : WrappedRecord(record) {}

llvm::StringRef getName() const {
return get()->getName();
}

/// Return the node for the base, if there is one.
ASTNode getBase() const {
return get()->getValueAsOptionalDef(BaseFieldName);
}

/// Is the corresponding class abstract?
bool isAbstract() const {
return get()->getValueAsBit(AbstractFieldName);
}

friend bool operator<(ASTNode lhs, ASTNode rhs) {
assert(lhs && rhs && "sorting null nodes");
return lhs.getName() < rhs.getName();
}
friend bool operator>(ASTNode lhs, ASTNode rhs) { return rhs < lhs; }
friend bool operator<=(ASTNode lhs, ASTNode rhs) { return !(rhs < lhs); }
friend bool operator>=(ASTNode lhs, ASTNode rhs) { return !(lhs < rhs); }

friend bool operator==(ASTNode lhs, ASTNode rhs) {
// This should handle null nodes.
return lhs.getRecord() == rhs.getRecord();
}
friend bool operator!=(ASTNode lhs, ASTNode rhs) { return !(lhs == rhs); }
};

class DeclNode : public ASTNode {
public:
DeclNode(llvm::Record *record = nullptr) : ASTNode(record) {}

llvm::StringRef getId() const;
std::string getClassName() const;
DeclNode getBase() const { return DeclNode(ASTNode::getBase().getRecord()); }

static llvm::StringRef getASTHierarchyName() {
return "Decl";
}
static llvm::StringRef getASTIdTypeName() {
return "Decl::Kind";
}
static llvm::StringRef getASTIdAccessorName() {
return "getKind";
}
static llvm::StringRef getTableGenNodeClassName() {
return DeclNodeClassName;
}
};

class TypeNode : public ASTNode {
public:
TypeNode(llvm::Record *record = nullptr) : ASTNode(record) {}

llvm::StringRef getId() const;
llvm::StringRef getClassName() const;
TypeNode getBase() const { return TypeNode(ASTNode::getBase().getRecord()); }

static llvm::StringRef getASTHierarchyName() {
return "Type";
}
static llvm::StringRef getASTIdTypeName() {
return "Type::TypeClass";
}
static llvm::StringRef getASTIdAccessorName() {
return "getTypeClass";
}
static llvm::StringRef getTableGenNodeClassName() {
return TypeNodeClassName;
}
};

class StmtNode : public ASTNode {
public:
StmtNode(llvm::Record *record = nullptr) : ASTNode(record) {}

std::string getId() const;
llvm::StringRef getClassName() const;
StmtNode getBase() const { return StmtNode(ASTNode::getBase().getRecord()); }

static llvm::StringRef getASTHierarchyName() {
return "Stmt";
}
static llvm::StringRef getASTIdTypeName() {
return "Stmt::StmtClass";
}
static llvm::StringRef getASTIdAccessorName() {
return "getStmtClass";
}
static llvm::StringRef getTableGenNodeClassName() {
return StmtNodeClassName;
}
};

/// The type of a property.
class PropertyType : public WrappedRecord {
public:
PropertyType(llvm::Record *record = nullptr) : WrappedRecord(record) {}

/// Is this a generic specialization (i.e. `Array<T>` or `Optional<T>`)?
bool isGenericSpecialization() const {
return get()->isAnonymous();
}

/// The abstract type name of the property. Doesn't work for generic
/// specializations.
llvm::StringRef getAbstractTypeName() const {
return get()->getName();
}

/// The C++ type name of the property. Doesn't work for generic
/// specializations.
llvm::StringRef getCXXTypeName() const {
return get()->getValueAsString(CXXTypeNameFieldName);
}
void emitCXXValueTypeName(bool forRead, llvm::raw_ostream &out) const;

/// Whether the C++ type should be passed around by reference.
bool shouldPassByReference() const {
return get()->getValueAsBit(PassByReferenceFieldName);
}

/// Whether the C++ type should have 'const' prepended when working with
/// a value of the type being written.
bool isConstWhenWriting() const {
return get()->getValueAsBit(ConstWhenWritingFieldName);
}

/// If this is `Array<T>`, return `T`; otherwise return null.
PropertyType getArrayElementType() const {
if (isSubClassOf(ArrayTypeClassName))
return get()->getValueAsDef(ArrayElementTypeFieldName);
return nullptr;
}

/// If this is `Optional<T>`, return `T`; otherwise return null.
PropertyType getOptionalElementType() const {
if (isSubClassOf(OptionalTypeClassName))
return get()->getValueAsDef(OptionalElementTypeFieldName);
return nullptr;
}

/// If this is a subclass type, return its superclass type.
PropertyType getSuperclassType() const {
if (isSubClassOf(SubclassPropertyTypeClassName))
return get()->getValueAsDef(SubclassBaseTypeFieldName);
return nullptr;
}

// Given that this is a subclass type, return the C++ name of its
// subclass type. This is just the bare class name, suitable for
// use in `cast<>`.
llvm::StringRef getSubclassClassName() const {
return get()->getValueAsString(SubclassClassNameFieldName);
}

/// Does this represent an enum type?
bool isEnum() const {
return isSubClassOf(EnumPropertyTypeClassName);
}

llvm::StringRef getPackOptionalCode() const {
return get()->getValueAsString(PackOptionalCodeFieldName);
}

llvm::StringRef getUnpackOptionalCode() const {
return get()->getValueAsString(UnpackOptionalCodeFieldName);
}

std::vector<llvm::Record*> getBufferElementTypes() const {
return get()->getValueAsListOfDefs(BufferElementTypesFieldName);
}
};

/// A property of an AST node.
class Property : public WrappedRecord {
public:
Property(llvm::Record *record = nullptr) : WrappedRecord(record) {}

/// Return the name of this property.
llvm::StringRef getName() const {
return get()->getValueAsString(NameFieldName);
}

/// Return the type of this property.
PropertyType getType() const {
return get()->getValueAsDef(TypeFieldName);
}

/// Return the class of which this is a property.
ASTNode getClass() const {
return get()->getValueAsDef(ClassFieldName);
}

/// Return the code for reading this property.
llvm::StringRef getReadCode() const {
return get()->getValueAsString(ReadFieldName);
}
};

/// A rule for how to create an AST node from its properties.
class CreationRule : public WrappedRecord {
public:
CreationRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}

/// Return the class for which this is a creation rule.
/// Should never be abstract.
ASTNode getClass() const {
return get()->getValueAsDef(ClassFieldName);
}

llvm::StringRef getCreationCode() const {
return get()->getValueAsString(CreateFieldName);
}
};

/// A rule which overrides the standard rules for serializing an AST node.
class OverrideRule : public WrappedRecord {
public:
OverrideRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}

/// Return the class for which this is an override rule.
/// Should never be abstract.
ASTNode getClass() const {
return get()->getValueAsDef(ClassFieldName);
}

/// Return a set of properties that are unnecessary when serializing
/// this AST node. Generally this is used for inherited properties
/// that are derived for this subclass.
std::vector<llvm::StringRef> getIgnoredProperties() const {
return get()->getValueAsListOfStrings(IgnoredPropertiesFieldName);
}
};

/// A visitor for an AST node hierarchy. Note that `base` can be null for
/// the root class.
template <class NodeClass>
using ASTNodeHierarchyVisitor =
llvm::function_ref<void(NodeClass node, NodeClass base)>;

void visitASTNodeHierarchyImpl(llvm::RecordKeeper &records,
llvm::StringRef nodeClassName,
ASTNodeHierarchyVisitor<ASTNode> visit);

template <class NodeClass>
void visitASTNodeHierarchy(llvm::RecordKeeper &records,
ASTNodeHierarchyVisitor<NodeClass> visit) {
visitASTNodeHierarchyImpl(records, NodeClass::getTableGenNodeClassName(),
[visit](ASTNode node, ASTNode base) {
visit(NodeClass(node.getRecord()),
NodeClass(base.getRecord()));
});
}

} // end namespace clang::tblgen
} // end namespace clang

#endif
2 changes: 2 additions & 0 deletions clang/utils/TableGen/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
set(LLVM_LINK_COMPONENTS Support)

add_tablegen(clang-tblgen CLANG
ASTTableGen.cpp
ClangASTNodesEmitter.cpp
ClangASTPropertiesEmitter.cpp
ClangAttrEmitter.cpp
ClangCommentCommandInfoEmitter.cpp
ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
Expand Down
39 changes: 0 additions & 39 deletions clang/utils/TableGen/ClangASTEmitters.h

This file was deleted.

84 changes: 42 additions & 42 deletions clang/utils/TableGen/ClangASTNodesEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "ClangASTEmitters.h"
#include "ASTTableGen.h"
#include "TableGenBackends.h"

#include "llvm/TableGen/Error.h"
Expand All @@ -21,18 +21,20 @@
#include <set>
#include <string>
using namespace llvm;
using namespace clang;
using namespace clang::tblgen;

/// ClangASTNodesEmitter - The top-level class emits .inc files containing
/// declarations of Clang statements.
///
namespace {
class ClangASTNodesEmitter {
// A map from a node to each of its derived nodes.
typedef std::multimap<Record*, Record*> ChildMap;
typedef std::multimap<ASTNode, ASTNode> ChildMap;
typedef ChildMap::const_iterator ChildIterator;

RecordKeeper &Records;
Record *Root = nullptr;
ASTNode Root;
const std::string &NodeClassName;
const std::string &BaseSuffix;
std::string MacroHierarchyName;
Expand All @@ -49,23 +51,23 @@ class ClangASTNodesEmitter {
const std::string &macroHierarchyName() {
assert(Root && "root node not yet derived!");
if (MacroHierarchyName.empty())
MacroHierarchyName = macroName(Root->getName());
MacroHierarchyName = macroName(Root.getName());
return MacroHierarchyName;
}

// Return the name to be printed in the base field. Normally this is
// the record's name plus the base suffix, but if it is the root node and
// the suffix is non-empty, it's just the suffix.
std::string baseName(Record &R) {
if (&R == Root && !BaseSuffix.empty())
std::string baseName(ASTNode node) {
if (node == Root && !BaseSuffix.empty())
return BaseSuffix;

return R.getName().str() + BaseSuffix;
return node.getName().str() + BaseSuffix;
}

void deriveChildTree();

std::pair<Record *, Record *> EmitNode(raw_ostream& OS, Record *Base);
std::pair<ASTNode, ASTNode> EmitNode(raw_ostream& OS, ASTNode Base);
public:
explicit ClangASTNodesEmitter(RecordKeeper &R, const std::string &N,
const std::string &S)
Expand All @@ -82,60 +84,58 @@ class ClangASTNodesEmitter {

// Returns the first and last non-abstract subrecords
// Called recursively to ensure that nodes remain contiguous
std::pair<Record *, Record *> ClangASTNodesEmitter::EmitNode(raw_ostream &OS,
Record *Base) {
std::string BaseName = macroName(Base->getName());
std::pair<ASTNode, ASTNode> ClangASTNodesEmitter::EmitNode(raw_ostream &OS,
ASTNode Base) {
std::string BaseName = macroName(Base.getName());

ChildIterator i = Tree.lower_bound(Base), e = Tree.upper_bound(Base);
bool HasChildren = (i != e);

Record *First = nullptr, *Last = nullptr;
if (!Base->getValueAsBit(AbstractFieldName))
ASTNode First, Last;
if (!Base.isAbstract())
First = Last = Base;

for (; i != e; ++i) {
Record *R = i->second;
bool Abstract = R->getValueAsBit(AbstractFieldName);
std::string NodeName = macroName(R->getName());
ASTNode Child = i->second;
bool Abstract = Child.isAbstract();
std::string NodeName = macroName(Child.getName());

OS << "#ifndef " << NodeName << "\n";
OS << "# define " << NodeName << "(Type, Base) "
<< BaseName << "(Type, Base)\n";
OS << "#endif\n";

if (Abstract)
OS << "ABSTRACT_" << macroHierarchyName() << "(" << NodeName << "("
<< R->getName() << ", " << baseName(*Base) << "))\n";
else
OS << NodeName << "(" << R->getName() << ", "
<< baseName(*Base) << ")\n";

if (Tree.find(R) != Tree.end()) {
const std::pair<Record *, Record *> &Result
= EmitNode(OS, R);
if (!First && Result.first)
First = Result.first;
if (Result.second)
Last = Result.second;
} else {
if (!Abstract) {
Last = R;

if (!First)
First = R;
}
}
if (Abstract) OS << "ABSTRACT_" << macroHierarchyName() << "(";
OS << NodeName << "(" << Child.getName() << ", " << baseName(Base) << ")";
if (Abstract) OS << ")";
OS << "\n";

auto Result = EmitNode(OS, Child);
assert(Result.first && Result.second && "node didn't have children?");

// Update the range of Base.
if (!First) First = Result.first;
Last = Result.second;

OS << "#undef " << NodeName << "\n\n";
}

if (First) {
assert (Last && "Got a first node but not a last node for a range!");
// If there aren't first/last nodes, it must be because there were no
// children and this node was abstract, which is not a sensible combination.
if (!First) {
PrintFatalError(Base.getLoc(), "abstract node has no children");
}
assert(Last && "set First without Last");

if (HasChildren) {
// Use FOO_RANGE unless this is the last of the ranges, in which case
// use LAST_FOO_RANGE.
if (Base == Root)
OS << "LAST_" << macroHierarchyName() << "_RANGE(";
else
OS << macroHierarchyName() << "_RANGE(";
OS << Base->getName() << ", " << First->getName() << ", "
<< Last->getName() << ")\n\n";
OS << Base.getName() << ", " << First.getName() << ", "
<< Last.getName() << ")\n\n";
}

return std::make_pair(First, Last);
Expand Down
658 changes: 658 additions & 0 deletions clang/utils/TableGen/ClangASTPropertiesEmitter.cpp

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions clang/utils/TableGen/ClangAttrEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//===----------------------------------------------------------------------===//

#include "TableGenBackends.h"
#include "ClangASTEmitters.h"
#include "ASTTableGen.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
Expand Down Expand Up @@ -102,9 +102,9 @@ static std::string ReadPCHRecord(StringRef type) {
return StringSwitch<std::string>(type)
.EndsWith("Decl *", "Record.GetLocalDeclAs<"
+ std::string(type, 0, type.size()-1) + ">(Record.readInt())")
.Case("TypeSourceInfo *", "Record.getTypeSourceInfo()")
.Case("TypeSourceInfo *", "Record.readTypeSourceInfo()")
.Case("Expr *", "Record.readExpr()")
.Case("IdentifierInfo *", "Record.getIdentifierInfo()")
.Case("IdentifierInfo *", "Record.readIdentifier()")
.Case("StringRef", "Record.readString()")
.Case("ParamIdx", "ParamIdx::deserialize(Record.readInt())")
.Default("Record.readInt()");
Expand Down Expand Up @@ -585,7 +585,7 @@ namespace {
OS << " " << getLowerName() << "Ptr = Record.readExpr();\n";
OS << " else\n";
OS << " " << getLowerName()
<< "Ptr = Record.getTypeSourceInfo();\n";
<< "Ptr = Record.readTypeSourceInfo();\n";
}

void writePCHWrite(raw_ostream &OS) const override {
Expand Down
200 changes: 96 additions & 104 deletions clang/utils/TableGen/ClangTypeNodesEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
//
//===----------------------------------------------------------------------===//

#include "ClangASTEmitters.h"
#include "ASTTableGen.h"
#include "TableGenBackends.h"

#include "llvm/ADT/StringRef.h"
Expand All @@ -57,6 +57,8 @@
#include <vector>

using namespace llvm;
using namespace clang;
using namespace clang::tblgen;

// These are spellings in the generated output.
#define TypeMacroName "TYPE"
Expand All @@ -70,147 +72,137 @@ using namespace llvm;

#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;
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)) {
}
TypeNodeEmitter(RecordKeeper &records, raw_ostream &out)
: Records(records), Out(out),
Types(Records.getAllDerivedDefinitions(TypeNodeClassName)) {
}

void emit();
void emit();

private:
void emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName,
StringRef args);
void emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName,
StringRef args);

void emitNodeInvocations();
void emitLastNodeInvocation();
void emitLeafNodeInvocations();
void emitNodeInvocations();
void emitLastNodeInvocation(TypeNode lastType);
void emitLeafNodeInvocations();

void addMacroToUndef(StringRef macroName);
void emitUndefs();
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();
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) {
StringRef fallbackMacroName,
StringRef args) {
Out << "#ifndef " << macroName << "\n";
Out << "# define " << macroName << args
<< " " << fallbackMacroName << args << "\n";
<< " " << 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";
}
TypeNode lastType;

visitASTNodeHierarchy<TypeNode>(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() {
// We check that this is non-empty earlier.
Out << "#ifdef " LastTypeMacroName "\n"
LastTypeMacroName "(" << getIdForType(Types.back()) << ")\n"
"#undef " LastTypeMacroName "\n"
"#endif\n";
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";
Out << "#ifdef " LeafTypeMacroName "\n";

for (auto type : Types) {
if (!type->isSubClassOf(LeafTypeClassName)) continue;
Out << LeafTypeMacroName "(" << getIdForType(type) << ")\n";
}
for (TypeNode type : Types) {
if (!type.isSubClassOf(LeafTypeClassName)) continue;
Out << LeafTypeMacroName "(" << type.getId() << ")\n";
}

Out << "#undef " LeafTypeMacroName "\n"
"#endif\n";
Out << "#undef " LeafTypeMacroName "\n"
"#endif\n";
}

void TypeNodeEmitter::addMacroToUndef(StringRef macroName) {
MacrosToUndef.push_back(macroName);
MacrosToUndef.push_back(macroName);
}

void TypeNodeEmitter::emitUndefs() {
for (auto &macroName : MacrosToUndef) {
Out << "#undef " << macroName << "\n";
}
for (auto &macroName : MacrosToUndef) {
Out << "#undef " << macroName << "\n";
}
}

void clang::EmitClangTypeNodes(RecordKeeper &records, raw_ostream &out) {
TypeNodeEmitter(records, out).emit();
TypeNodeEmitter(records, out).emit();
}
26 changes: 25 additions & 1 deletion clang/utils/TableGen/TableGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//===----------------------------------------------------------------------===//

#include "TableGenBackends.h" // Declares all backends.
#include "ClangASTEmitters.h"
#include "ASTTableGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
Expand Down Expand Up @@ -42,13 +42,17 @@ enum ActionType {
GenClangAttrParsedAttrKinds,
GenClangAttrTextNodeDump,
GenClangAttrNodeTraverse,
GenClangBasicReader,
GenClangBasicWriter,
GenClangDiagsDefs,
GenClangDiagGroups,
GenClangDiagsIndexName,
GenClangCommentNodes,
GenClangDeclNodes,
GenClangStmtNodes,
GenClangTypeNodes,
GenClangTypeReader,
GenClangTypeWriter,
GenClangOpcodes,
GenClangSACheckers,
GenClangCommentHTMLTags,
Expand Down Expand Up @@ -131,6 +135,10 @@ cl::opt<ActionType> Action(
"Generate Clang diagnostic groups"),
clEnumValN(GenClangDiagsIndexName, "gen-clang-diags-index-name",
"Generate Clang diagnostic name index"),
clEnumValN(GenClangBasicReader, "gen-clang-basic-reader",
"Generate Clang BasicReader classes"),
clEnumValN(GenClangBasicWriter, "gen-clang-basic-writer",
"Generate Clang BasicWriter classes"),
clEnumValN(GenClangCommentNodes, "gen-clang-comment-nodes",
"Generate Clang AST comment nodes"),
clEnumValN(GenClangDeclNodes, "gen-clang-decl-nodes",
Expand All @@ -139,6 +147,10 @@ cl::opt<ActionType> Action(
"Generate Clang AST statement nodes"),
clEnumValN(GenClangTypeNodes, "gen-clang-type-nodes",
"Generate Clang AST type nodes"),
clEnumValN(GenClangTypeReader, "gen-clang-type-reader",
"Generate Clang AbstractTypeReader class"),
clEnumValN(GenClangTypeWriter, "gen-clang-type-writer",
"Generate Clang AbstractTypeWriter class"),
clEnumValN(GenClangOpcodes, "gen-clang-opcodes",
"Generate Clang constexpr interpreter opcodes"),
clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers",
Expand Down Expand Up @@ -276,6 +288,18 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangTypeNodes:
EmitClangTypeNodes(Records, OS);
break;
case GenClangTypeReader:
EmitClangTypeReader(Records, OS);
break;
case GenClangTypeWriter:
EmitClangTypeWriter(Records, OS);
break;
case GenClangBasicReader:
EmitClangBasicReader(Records, OS);
break;
case GenClangBasicWriter:
EmitClangBasicWriter(Records, OS);
break;
case GenClangOpcodes:
EmitClangOpcodes(Records, OS);
break;
Expand Down
5 changes: 4 additions & 1 deletion clang/utils/TableGen/TableGenBackends.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ namespace clang {
void EmitClangDeclContext(llvm::RecordKeeper &RK, llvm::raw_ostream &OS);
void EmitClangASTNodes(llvm::RecordKeeper &RK, llvm::raw_ostream &OS,
const std::string &N, const std::string &S);
void EmitClangBasicReader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangBasicWriter(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangTypeNodes(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);

void EmitClangTypeReader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangTypeWriter(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangAttrParserStringSwitches(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangAttrSubjectMatchRulesParserStringSwitches(
Expand Down