summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-02-20 15:37:11 -0800
committerGitHub <noreply@github.com>2024-02-20 15:37:11 -0800
commita62be597990966b9516995650baf750ee6a0146b (patch)
tree1741b3d5b5859319f278aa6ab821a2f801fd8e08 /source
parent4d20fd329956ac89408b1628a8291fea01bc9a6d (diff)
Support link time type specialization. (#3604)
Diffstat (limited to 'source')
-rw-r--r--source/core/slang-list.h2
-rw-r--r--source/slang/slang-ast-decl.cpp15
-rw-r--r--source/slang/slang-ast-decl.h13
-rw-r--r--source/slang/slang-ast-dump.cpp4
-rw-r--r--source/slang/slang-ast-support-types.h3
-rw-r--r--source/slang/slang-check-conformance.cpp53
-rw-r--r--source/slang/slang-check-decl.cpp40
-rw-r--r--source/slang/slang-check-impl.h6
-rw-r--r--source/slang/slang-check-modifier.cpp3
-rw-r--r--source/slang/slang-diagnostic-defs.h3
-rw-r--r--source/slang/slang-lower-to-ir.cpp14
-rw-r--r--source/slang/slang-parser.cpp5
12 files changed, 149 insertions, 12 deletions
diff --git a/source/core/slang-list.h b/source/core/slang-list.h
index 250b6dc49..c0fe28937 100644
--- a/source/core/slang-list.h
+++ b/source/core/slang-list.h
@@ -570,7 +570,7 @@ namespace Slang
}
template<typename T2>
- int binarySearch(const T2& obj)
+ Index binarySearch(const T2& obj)
{
return binarySearch(obj,
[](T & curObj, const T2 & thatObj)->int
diff --git a/source/slang/slang-ast-decl.cpp b/source/slang/slang-ast-decl.cpp
index 9dbd006a0..cd9c43410 100644
--- a/source/slang/slang-ast-decl.cpp
+++ b/source/slang/slang-ast-decl.cpp
@@ -136,4 +136,19 @@ InterfaceDecl* ThisTypeConstraintDecl::getInterfaceDecl()
return as<InterfaceDecl>(parentDecl->parentDecl);
}
+void AggTypeDecl::addTag(TypeTag tag)
+{
+ typeTags = (TypeTag)((int)tag | (int)tag);
+}
+
+bool AggTypeDecl::hasTag(TypeTag tag)
+{
+ return ((int)typeTags & (int)tag) != 0;
+}
+
+void AggTypeDecl::unionTagsWith(TypeTag other)
+{
+ addTag(other);
+}
+
} // namespace Slang
diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h
index 5d8023eaf..7a4d46947 100644
--- a/source/slang/slang-ast-decl.h
+++ b/source/slang/slang-ast-decl.h
@@ -130,11 +130,24 @@ class ExtensionDecl : public AggTypeDeclBase
TypeExp targetType;
};
+enum class TypeTag
+{
+ None = 0,
+ Unsized = 1,
+ Incomplete = 2
+};
+
// Declaration of a type that represents some sort of aggregate
class AggTypeDecl : public AggTypeDeclBase
{
SLANG_ABSTRACT_AST_CLASS(AggTypeDecl)
+ TypeTag typeTags = TypeTag::None;
+
+ void unionTagsWith(TypeTag other);
+ void addTag(TypeTag tag);
+ bool hasTag(TypeTag tag);
+
FilteredMemberList<VarDecl> getFields()
{
return getMembersOfType<VarDecl>();
diff --git a/source/slang/slang-ast-dump.cpp b/source/slang/slang-ast-dump.cpp
index 9c40fb12b..ccd9b9ee7 100644
--- a/source/slang/slang-ast-dump.cpp
+++ b/source/slang/slang-ast-dump.cpp
@@ -343,6 +343,10 @@ struct ASTDumpContext
{
m_writer->emit((int)v);
}
+ void dump(TypeTag tag)
+ {
+ m_writer->emit((int)tag);
+ }
void dump(const String& string)
{
dump(string.getUnownedSlice());
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index c1984910c..d3529b963 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -1503,6 +1503,9 @@ namespace Slang
// The type witnessesd by the witness table (a concrete type).
Type* witnessedType;
+ // Whether or not this witness table is an extern declaration.
+ bool isExtern = false;
+
// Satisfying values of each requirement.
List<KeyValuePair<Decl*, RequirementWitness>> m_requirements;
diff --git a/source/slang/slang-check-conformance.cpp b/source/slang/slang-check-conformance.cpp
index 4376b1135..726572d08 100644
--- a/source/slang/slang-check-conformance.cpp
+++ b/source/slang/slang-check-conformance.cpp
@@ -242,6 +242,59 @@ namespace Slang
return isSubtype(type, m_astBuilder->getDiffInterfaceType());
}
+ bool SemanticsVisitor::doesTypeHaveTag(Type* type, TypeTag tag)
+ {
+ if (auto arrayType = as<ArrayExpressionType>(type))
+ {
+ return doesTypeHaveTag(arrayType->getElementType(), tag);
+ }
+ if (auto modifiedType = as<ModifiedType>(type))
+ {
+ return doesTypeHaveTag(modifiedType->getBase(), tag);
+ }
+ if (auto declRefType = as<DeclRefType>(type))
+ {
+ if (auto aggTypeDecl = as<AggTypeDecl>(declRefType->getDeclRef()))
+ return aggTypeDecl.getDecl()->hasTag(tag);
+ }
+ return false;
+ }
+
+ TypeTag SemanticsVisitor::getTypeTags(Type* type)
+ {
+ if (auto arrayType = as<ArrayExpressionType>(type))
+ {
+ return getTypeTags(arrayType->getElementType());
+ }
+ if (auto modifiedType = as<ModifiedType>(type))
+ {
+ return getTypeTags(modifiedType->getBase());
+ }
+ if (auto declRefType = as<DeclRefType>(type))
+ {
+ if (auto aggTypeDecl = as<AggTypeDecl>(declRefType->getDeclRef()))
+ return aggTypeDecl.getDecl()->typeTags;
+ }
+ return TypeTag::None;
+ }
+
+
+ Type* SemanticsVisitor::getBufferElementType(Type* type)
+ {
+ if (auto arrType = as<ArrayExpressionType>(type))
+ return getBufferElementType(arrType->getElementType());
+ if (auto modifiedType = as<ModifiedType>(type))
+ return getBufferElementType(modifiedType->getBase());
+ if (auto constantBuffer = as<ConstantBufferType>(type))
+ return constantBuffer->getElementType();
+ if (auto structuredBuffer = as<HLSLStructuredBufferTypeBase>(type))
+ return structuredBuffer->getElementType();
+ if (auto storageBuffer = as<GLSLShaderStorageBufferType>(type))
+ return storageBuffer->getElementType();
+ return nullptr;
+ }
+
+
SubtypeWitness* SemanticsVisitor::tryGetInterfaceConformanceWitness(
Type* type,
Type* interfaceType)
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 3fb2725e2..dc888ccda 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -302,6 +302,8 @@ namespace Slang
void visitFunctionDeclBase(FunctionDeclBase* funcDecl);
void visitParamDecl(ParamDecl* paramDecl);
+
+ void visitAggTypeDecl(AggTypeDecl* aggTypeDecl);
};
template<typename VisitorType>
@@ -1705,6 +1707,15 @@ namespace Slang
}
}
+ // Propagate type tags.
+ if (auto parentAggTypeDecl = as<AggTypeDecl>(getParentDecl(varDecl)))
+ {
+ if (auto varDeclRefType = as<DeclRefType>(varDecl->type.type))
+ {
+ parentAggTypeDecl->unionTagsWith(getTypeTags(varDecl->type.type));
+ }
+ }
+
checkVisibility(varDecl);
}
@@ -1722,11 +1733,20 @@ namespace Slang
{
addModifier(structDecl, m_astBuilder->create<NVAPIMagicModifier>());
}
+
+ if (structDecl->hasModifier<ExternModifier>())
+ {
+ structDecl->addTag(TypeTag::Incomplete);
+ }
checkVisibility(structDecl);
}
void SemanticsDeclHeaderVisitor::visitClassDecl(ClassDecl* classDecl)
{
+ if (classDecl->hasModifier<ExternModifier>())
+ {
+ classDecl->addTag(TypeTag::Incomplete);
+ }
checkVisibility(classDecl);
}
@@ -1812,6 +1832,13 @@ namespace Slang
varDecl->initExpr = CompleteOverloadCandidate(overloadContext, *overloadContext.bestCandidate);
}
}
+ if (auto elementType = getBufferElementType(varDecl->getType()))
+ {
+ if (doesTypeHaveTag(elementType, TypeTag::Incomplete))
+ {
+ getSink()->diagnose(varDecl->type.exp->loc, Diagnostics::incompleteTypeCannotBeUsedInBuffer, elementType);
+ }
+ }
maybeRegisterDifferentiableType(getASTBuilder(), varDecl->getType());
}
@@ -4784,6 +4811,9 @@ namespace Slang
SubtypeWitness* subIsSuperWitness,
WitnessTable* witnessTable)
{
+ if (witnessTable->isExtern)
+ return true;
+
if (auto supereclRefType = as<DeclRefType>(superType))
{
auto superTypeDeclRef = supereclRefType->getDeclRef();
@@ -4896,6 +4926,7 @@ namespace Slang
witnessTable = new WitnessTable();
witnessTable->baseType = superType;
witnessTable->witnessedType = subType;
+ witnessTable->isExtern = parentDecl->hasModifier<ExternModifier>();
inheritanceDecl->witnessTable = witnessTable;
}
@@ -5179,6 +5210,7 @@ namespace Slang
// order) is allowed to declare a base `class` type.
//
SLANG_OUTER_SCOPE_CONTEXT_DECL_RAII(this, decl);
+
Index inheritanceClauseCounter = 0;
for (auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>())
{
@@ -6544,6 +6576,14 @@ namespace Slang
}
}
+ void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl)
+ {
+ if (aggTypeDecl->hasTag(TypeTag::Incomplete) && aggTypeDecl->hasModifier<HLSLExportModifier>())
+ {
+ getSink()->diagnose(aggTypeDecl->loc, Diagnostics::cannotExportIncompleteType, aggTypeDecl);
+ }
+ }
+
void SemanticsDeclHeaderVisitor::cloneModifiers(Decl* dest, Decl* src)
{
dest->modifiers = src->modifiers;
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index 3af85b73d..ba8e2f4cd 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -1957,6 +1957,12 @@ namespace Slang
bool isTypeDifferentiable(Type* type);
+ bool doesTypeHaveTag(Type* type, TypeTag tag);
+
+ TypeTag getTypeTags(Type* type);
+
+ Type* getBufferElementType(Type* type);
+
/// Check whether `subType` is a sub-type of `superTypeDeclRef`,
/// and return a witness to the sub-type relationship if it holds
/// (return null otherwise).
diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp
index 9117eb6ec..a4e906ac9 100644
--- a/source/slang/slang-check-modifier.cpp
+++ b/source/slang/slang-check-modifier.cpp
@@ -1109,7 +1109,8 @@ namespace Slang
case ASTNodeType::HLSLExportModifier:
case ASTNodeType::ExternCppModifier:
return as<VarDeclBase>(decl) || as<AggTypeDeclBase>(decl) || as<NamespaceDeclBase>(decl) || as<CallableDecl>(decl)
- || as<TypeDefDecl>(decl) || as<PropertyDecl>(decl) || as<SyntaxDecl>(decl) || as<AttributeDecl>(decl);
+ || as<TypeDefDecl>(decl) || as<PropertyDecl>(decl) || as<SyntaxDecl>(decl) || as<AttributeDecl>(decl)
+ || as<InheritanceDecl>(decl);
case ASTNodeType::ExportedModifier:
return as<ImportDecl>(decl);
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index ac1f9aff9..722085744 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -438,6 +438,9 @@ DIAGNOSTIC(31155, Error, customDerivativeNotAllowedForMemberFunctionsOfDifferent
DIAGNOSTIC(31200, Warning, deprecatedUsage, "$0 has been deprecated: $1")
DIAGNOSTIC(31201, Error, modifierNotAllowed, "modifier '$0' is not allowed here.")
DIAGNOSTIC(31202, Error, duplicateModifier, "modifier '$0' is redundant or conflicting with existing modifier '$1'")
+DIAGNOSTIC(31203, Error, cannotExportIncompleteType, "cannot export incomplete type '$0'")
+DIAGNOSTIC(31204, Error, incompleteTypeCannotBeUsedInBuffer, "incomplete type '$0' cannot be used in a buffer")
+
// Enums
DIAGNOSTIC(32000, Error, invalidEnumTagType, "invalid tag type for 'enum': '$0'")
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 8531e4029..b560bb156 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -657,17 +657,11 @@ bool isFromStdLib(Decl* decl)
bool isImportedDecl(IRGenContext* context, Decl* decl)
{
// If the declaration has the extern attribute then it must be imported
- // from another module
+ // from another module.
+ // Note that `extern` declarations will have a mangled name that does not
+ // include the module name so the linking step can resolve them correctly.
//
- // The [__extern] attribute is a very special case feature (aka "a hack") that allows a symbol to be declared
- // as if it is part of the current module for AST purposes, but then expects to be imported from another IR module.
- // For that linkage to work, both the exporting and importing modules must have the same name (which would
- // usually indicate that they are the same module).
- //
- // Note that in practice for matching during linking uses the fully qualified name - including module name.
- // Thus using extern __attribute isn't useful for symbols that are imported via `import`, only symbols
- // that notionally come from the same module but are split into separate compilations (as can be done with -module-name)
- if (decl->findModifier<ExternAttribute>())
+ if (decl->findModifier<ExternAttribute>() || decl->findModifier<ExternModifier>())
{
return true;
}
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index e0ffba53c..b89b93138 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -3232,6 +3232,9 @@ namespace Slang
inheritanceDecl->base = base;
AddMember(decl, inheritanceDecl);
+
+ if (parser->pendingModifiers->hasModifier<ExternModifier>())
+ addModifier(inheritanceDecl, parser->astBuilder->create<ExternModifier>());
} while (AdvanceIf(parser, TokenType::Comma));
}
@@ -4730,6 +4733,8 @@ namespace Slang
// We allow for an inheritance clause on a `struct`
// so that it can conform to interfaces.
parseOptionalInheritanceClause(this, rs);
+ if (AdvanceIf(this, TokenType::Semicolon))
+ return rs;
parseDeclBody(this, rs);
return rs;
});