Skip to content

Commit

Permalink
Add the ability for properties to be conditional on other properties.
Browse files Browse the repository at this point in the history
This will be required by TemplateName.
  • Loading branch information
rjmccall committed Dec 16, 2019
1 parent 256ec99 commit 6887ccf
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 19 deletions.
12 changes: 11 additions & 1 deletion clang/include/clang/AST/PropertiesBase.td
Expand Up @@ -107,7 +107,7 @@ def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; }
SubclassPropertyType<"ValueDecl", DeclRef>;
def ElaboratedTypeKeyword : EnumPropertyType;
def ExtParameterInfo : PropertyType<"FunctionProtoType::ExtParameterInfo">;
def Identifier : PropertyType<"IdentifierInfo*">;
def Identifier : RefPropertyType<"IdentifierInfo"> { let ConstWhenWriting = 1; }
def NestedNameSpecifier : PropertyType<"NestedNameSpecifier *">;
def NestedNameSpecifierKind :
EnumPropertyType<"NestedNameSpecifier::SpecifierKind">;
Expand Down Expand Up @@ -158,6 +158,16 @@ class Property<string name, PropertyType type> {
/// A function for reading the property, expressed in terms of a variable
/// "node".
code Read;

/// Code specifying when this property is available. Can be defined
/// in terms of other properties, in which case this property must be
/// read/written after those properties. Using this will make the
/// value Optional when deserializing.
///
/// FIXME: the emitter doesn't yet force dependent properties to be
/// read/written later; this only works if the properties used in the
/// condition happen to be written first.
code Conditional = "";
}

/// A rule for declaring helper variables when read properties from a
Expand Down
6 changes: 4 additions & 2 deletions clang/include/clang/AST/TypeProperties.td
Expand Up @@ -469,7 +469,8 @@ let Class = ElaboratedType in {
let Read = [{ node->getNamedType() }];
}
def : Property<"ownedTag", Optional<TagDeclRef>> {
let Read = [{ makeOptionalFromPointer(node->getOwnedTagDecl()) }];
let Read = [{ makeOptionalFromPointer(
const_cast<const TagDecl *>(node->getOwnedTagDecl())) }];
}

def : Creator<[{
Expand Down Expand Up @@ -631,7 +632,8 @@ let Class = TemplateTypeParmType in {
let Read = [{ node->isParameterPack() }];
}
def : Property<"declaration", Optional<TemplateTypeParmDeclRef>> {
let Read = [{ makeOptionalFromPointer(node->getDecl()) }];
let Read = [{ makeOptionalFromPointer(
const_cast<const TemplateTypeParmDecl*>(node->getDecl())) }];
}

def : Creator<[{
Expand Down
6 changes: 6 additions & 0 deletions clang/utils/TableGen/ASTTableGen.h
Expand Up @@ -57,6 +57,7 @@
#define CXXTypeNameFieldName "CXXName"
#define PassByReferenceFieldName "PassByReference"
#define ConstWhenWritingFieldName "ConstWhenWriting"
#define ConditionalCodeFieldName "Conditional"
#define PackOptionalCodeFieldName "PackOptional"
#define UnpackOptionalCodeFieldName "UnpackOptional"
#define BufferElementTypesFieldName "BufferElementTypes"
Expand Down Expand Up @@ -401,6 +402,11 @@ class Property : public WrappedRecord {
return get()->getValueAsString(ReadFieldName);
}

/// Return the code for determining whether to add this property.
llvm::StringRef getCondition() const {
return get()->getValueAsString(ConditionalCodeFieldName);
}

static llvm::StringRef getTableGenNodeClassName() {
return PropertyClassName;
}
Expand Down
70 changes: 54 additions & 16 deletions clang/utils/TableGen/ClangASTPropertiesEmitter.cpp
Expand Up @@ -188,6 +188,10 @@ class ASTPropsEmitter {
ignoredProperties.insert(list.begin(), list.end());
}

// TODO: we should sort the properties in various ways
// - put arrays at the end to enable abbreviations
// - put conditional properties after properties used in the condition

visitAllNodesWithInfo(derived, derivedInfo,
[&](HasProperties node, const NodeInfo &info) {
for (Property prop : info.Properties) {
Expand Down Expand Up @@ -244,11 +248,12 @@ class ASTPropsEmitter {

void emitReadOfProperty(StringRef readerName, Property property);
void emitReadOfProperty(StringRef readerName, StringRef name,
PropertyType type);
PropertyType type, StringRef condition = "");

void emitWriteOfProperty(StringRef writerName, Property property);
void emitWriteOfProperty(StringRef writerName, StringRef name,
PropertyType type, StringRef readCode);
PropertyType type, StringRef readCode,
StringRef condition = "");

void emitBasicReaderWriterFile(const ReaderWriterInfo &info);
void emitDispatcherTemplate(const ReaderWriterInfo &info);
Expand Down Expand Up @@ -499,12 +504,14 @@ static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
/// Emit code to read the given property in a node-reader method.
void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
Property property) {
emitReadOfProperty(readerName, property.getName(), property.getType());
emitReadOfProperty(readerName, property.getName(), property.getType(),
property.getCondition());
}

void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
StringRef name,
PropertyType type) {
PropertyType type,
StringRef condition) {
// Declare all the necessary buffers.
auto bufferTypes = type.getBufferElementTypes();
for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
Expand All @@ -518,33 +525,65 @@ void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
// get a pr-value back from read(), and we should be able to forward
// that in the creation rule.
Out << " ";
if (!condition.empty()) Out << "llvm::Optional<";
type.emitCXXValueTypeName(true, Out);
Out << " " << name << " = " << readerName << ".find(\"" << name << "\")."
if (!condition.empty()) Out << ">";
Out << " " << name;

if (condition.empty()) {
Out << " = ";
} else {
Out << ";\n"
" if (" << condition << ") {\n"
" " << name << ".emplace(";
}

Out << readerName << ".find(\"" << name << "\")."
<< (type.isGenericSpecialization() ? "template " : "") << "read";
emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
Out << "(";
for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
}
Out << ");\n";
Out << ")";

if (condition.empty()) {
Out << ";\n";
} else {
Out << ");\n"
" }\n";
}
}

/// Emit code to write the given property in a node-writer method.
void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
Property property) {
emitWriteOfProperty(writerName, property.getName(), property.getType(),
property.getReadCode());
property.getReadCode(), property.getCondition());
}

void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
StringRef name,
PropertyType type,
StringRef readCode) {
StringRef readCode,
StringRef condition) {
if (!condition.empty()) {
Out << " if (" << condition << ") {\n";
}

// Focus down to the property:
// W.find("prop").write##ValueType(value);
Out << " " << writerName << ".find(\"" << name << "\").write";
// T prop = <READ>;
// W.find("prop").write##ValueType(prop);
Out << " ";
type.emitCXXValueTypeName(false, Out);
Out << " " << name << " = (" << readCode << ");\n"
" " << writerName << ".find(\"" << name << "\").write";
emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);
Out << "(" << readCode << ");\n";
Out << "(" << name << ");\n";

if (!condition.empty()) {
Out << " }\n";
}
}

/// Emit an .inc file that defines the AbstractFooReader class
Expand Down Expand Up @@ -775,11 +814,10 @@ void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type,
if (info.IsReader) {
emitReadOfProperty(subvar, kindProperty, kindType);
} else {
// Read the kind into a local variable.
Out << " ";
kindType.emitCXXValueTypeName(/*for read*/ false, Out);
Out << " " << kindProperty << " = " << kindRule.getReadCode() << ";\n";
emitWriteOfProperty(subvar, kindProperty, kindType, kindProperty);
// Write the property. Note that this will implicitly read the
// kind into a local variable with the right name.
emitWriteOfProperty(subvar, kindProperty, kindType,
kindRule.getReadCode());
}

// Prepare a ReaderWriterInfo with a helper variable that will use
Expand Down

0 comments on commit 6887ccf

Please sign in to comment.