summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArielG-NV <159081215+ArielG-NV@users.noreply.github.com>2025-05-21 21:11:01 -0700
committerGitHub <noreply@github.com>2025-05-22 04:11:01 +0000
commit27c6e9b01f7386263bde90e16812be46327015c2 (patch)
treea640d6882da0c9ee90ef64872b1b94c721039cdf
parent21346ded32be9091389ca53815c1ba56feff8a01 (diff)
Initial `dyn` keyword support & `-lang 2026` compiler option (#7172)
fixes: [#7143](https://github.com/shader-slang/slang/issues/7143) fixes: [#7146](https://github.com/shader-slang/slang/issues/7146) Goal of PR: * This PR is part of the larger #7115 refactor to how dynamic dispatch works. * The first step is to add the `-std <std-revision>` flag. * The second step is to provide basic `dyn` keyword support in AST. This does not include `varDecl` support since most of these interactions require `some` keyword support. Future PR(s) goal: * Support `some` keyword in AST. With this we will also implement all varDecl interactions between `dyn` and `some`. * Add IR support for `some` and `dyn`. Breakdown of PR: * most of the logic is in `validateDyn.*`. This was done so that in the future when we implement more features we will have an easy time removing/adding restrictions to `dyn` interfaces. Breaking changes: * As per spec (https://github.com/shader-slang/spec/pull/14/files), any type conforming to a `dyn` interface errors if member list contains one of the following: opaque type, non copyable type, or unsized type. * Due to the breaking change, the test `tests\compute\dynamic-dispatch-bindless-texture.slang` is incorrect. This has been fixed.
-rw-r--r--docs/command-line-slangc-reference.md23
-rw-r--r--docs/user-guide/a3-02-reference-capability-atoms.md3
-rw-r--r--include/slang.h14
-rw-r--r--source/core/slang-type-text-util.cpp16
-rw-r--r--source/core/slang-type-text-util.h5
-rw-r--r--source/slang/slang-ast-modifier.h6
-rw-r--r--source/slang/slang-check-decl.cpp198
-rw-r--r--source/slang/slang-check-modifier.cpp3
-rw-r--r--source/slang/slang-compiler-options.cpp2
-rw-r--r--source/slang/slang-diagnostic-defs.h56
-rw-r--r--source/slang/slang-options.cpp36
-rw-r--r--source/slang/slang-parser.cpp2
-rw-r--r--tests/compute/dynamic-dispatch-bindless-texture.slang36
-rw-r--r--tests/compute/interface-qualifiers/dyn-on-type-uses.slang186
-rw-r--r--tests/compute/interface-qualifiers/some-and-dyn-vardecl-uses.slang1
15 files changed, 555 insertions, 32 deletions
diff --git a/docs/command-line-slangc-reference.md b/docs/command-line-slangc-reference.md
index 89e7f0b4c..d0e94a622 100644
--- a/docs/command-line-slangc-reference.md
+++ b/docs/command-line-slangc-reference.md
@@ -22,6 +22,7 @@ slangc -help-style markdown -h
* [Deprecated](#Deprecated)
* [compiler](#compiler)
* [language](#language)
+* [std-revision](#std-revision)
* [archive-type](#archive-type)
* [line-directive-mode](#line-directive-mode)
* [debug-info-format](#debug-info-format)
@@ -223,6 +224,14 @@ Display the build version. This is the contents of git describe --tags.
It is typically only set from automated builds(such as distros available on github).A user build will by default be 'unknown'.
+<a id="std"></a>
+### -std
+
+**-std &lt;[std-revision](#std-revision)&gt;**
+
+Specifies the language standard that should be used.
+
+
<a id="warnings-as-errors"></a>
### -warnings-as-errors
@@ -742,6 +751,11 @@ Enable GLSL as an input language.
Enable experimental compiler passes
+<a id="enable-experimental-dynamic-dispatch"></a>
+### -enable-experimental-dynamic-dispatch
+Enable experimental dynamic dispatch features
+
+
<a id="embed-downstream-ir"></a>
### -embed-downstream-ir
Embed downstream IR into emitted slang IR
@@ -884,6 +898,15 @@ Language
* `hlsl` : HLSL language
* `cu`, `cuda` : CUDA
+<a id="std-revision"></a>
+## std-revision
+
+Std Revision
+
+* `unknown` : Unknown
+* `2025`, `default` : Slang language rules for 2025 and older
+* `2026` : Slang language rules for 2026 and newer
+
<a id="archive-type"></a>
## archive-type
diff --git a/docs/user-guide/a3-02-reference-capability-atoms.md b/docs/user-guide/a3-02-reference-capability-atoms.md
index 4596e8fed..9c2f6ca0a 100644
--- a/docs/user-guide/a3-02-reference-capability-atoms.md
+++ b/docs/user-guide/a3-02-reference-capability-atoms.md
@@ -669,6 +669,9 @@ Extensions
`GL_EXT_shader_atomic_int64`
> Represents the GL_EXT_shader_atomic_int64 extension.
+`GL_EXT_shader_explicit_arithmetic_types`
+> Represents the GL_EXT_shader_explicit_arithmetic_types extension.
+
`GL_EXT_shader_explicit_arithmetic_types_int64`
> Represents the GL_EXT_shader_explicit_arithmetic_types_int64 extension.
diff --git a/include/slang.h b/include/slang.h
index d65362762..4164ce9e9 100644
--- a/include/slang.h
+++ b/include/slang.h
@@ -627,6 +627,17 @@ typedef uint32_t SlangSizeT;
SLANG_TARGET_COUNT_OF,
};
+ typedef int SlangStdRevisionIntegral;
+ enum SlangStdRevision : SlangStdRevisionIntegral
+ {
+ SLANG_STD_REVISION_UNKNOWN,
+ SLANG_STD_REVISION_2025,
+ SLANG_STD_REVISION_2026,
+ SLANG_STD_REVISION_COUNT_OF,
+
+ SLANG_STD_REVISION_DEFAULT = SLANG_STD_REVISION_2025,
+ };
+
/* A "container format" describes the way that the outputs
for multiple files, entry points, targets, etc. should be
combined into a single artifact for output. */
@@ -1021,6 +1032,9 @@ typedef uint32_t SlangSizeT;
SkipDownstreamLinking, // bool, experimental
DumpModule,
+
+ EnableExperimentalDynamicDispatch, // bool, experimental
+ StdRevision, // intValue0: SlangStdRevision
CountOf,
};
diff --git a/source/core/slang-type-text-util.cpp b/source/core/slang-type-text-util.cpp
index 2261ed614..4797395b7 100644
--- a/source/core/slang-type-text-util.cpp
+++ b/source/core/slang-type-text-util.cpp
@@ -99,6 +99,12 @@ static const NamesDescriptionValue s_languageInfos[] = {
{SLANG_SOURCE_LANGUAGE_CUDA, "cu,cuda", "CUDA"},
};
+static const NamesDescriptionValue s_stdRevisionInfos[] = {
+ {SLANG_STD_REVISION_UNKNOWN, "unknown", "Unknown"},
+ {SLANG_STD_REVISION_2025, "2025,default", "Slang language rules for 2025 and older"},
+ {SLANG_STD_REVISION_2026, "2026", "Slang language rules for 2026 and newer"},
+};
+
static const NamesDescriptionValue s_compilerInfos[] = {
{SLANG_PASS_THROUGH_NONE, "none", "Unknown"},
{SLANG_PASS_THROUGH_FXC, "fxc", "FXC HLSL compiler"},
@@ -217,6 +223,11 @@ static const NamesDescriptionValue s_fileSystemTypes[] = {
return makeConstArrayView(s_languageInfos);
}
+/* static */ ConstArrayView<NamesDescriptionValue> TypeTextUtil::getStdRevisionInfos()
+{
+ return makeConstArrayView(s_stdRevisionInfos);
+}
+
/* static */ ConstArrayView<NamesDescriptionValue> TypeTextUtil::getCompilerInfos()
{
return makeConstArrayView(s_compilerInfos);
@@ -317,6 +328,11 @@ static const NamesDescriptionValue s_fileSystemTypes[] = {
return NameValueUtil::findValue(getLanguageInfos(), text, SLANG_SOURCE_LANGUAGE_UNKNOWN);
}
+/* static */ SlangStdRevision TypeTextUtil::findStdRevision(const UnownedStringSlice& text)
+{
+ return NameValueUtil::findValue(getStdRevisionInfos(), text, SLANG_STD_REVISION_UNKNOWN);
+}
+
/* static */ SlangPassThrough TypeTextUtil::findPassThrough(const UnownedStringSlice& slice)
{
return NameValueUtil::findValue(getCompilerInfos(), slice, SLANG_PASS_THROUGH_NONE);
diff --git a/source/core/slang-type-text-util.h b/source/core/slang-type-text-util.h
index 730888254..bc136c3ab 100644
--- a/source/core/slang-type-text-util.h
+++ b/source/core/slang-type-text-util.h
@@ -33,6 +33,8 @@ struct TypeTextUtil
/// Get the language infos
static ConstArrayView<NamesDescriptionValue> getLanguageInfos();
+ /// Get the std revision infos
+ static ConstArrayView<NamesDescriptionValue> getStdRevisionInfos();
/// Get the compiler infos
static ConstArrayView<NamesDescriptionValue> getCompilerInfos();
/// Get the archive type infos
@@ -71,6 +73,9 @@ struct TypeTextUtil
/// Given a source language name returns a source language. Name here is distinct from extension
static SlangSourceLanguage findSourceLanguage(const UnownedStringSlice& text);
+ /// Given a std revision returns a std revision.
+ static SlangStdRevision findStdRevision(const UnownedStringSlice& text);
+
/// Given a name returns the pass through
static SlangPassThrough findPassThrough(const UnownedStringSlice& slice);
static SlangResult findPassThrough(
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h
index ac1960685..1a65cf4a9 100644
--- a/source/slang/slang-ast-modifier.h
+++ b/source/slang/slang-ast-modifier.h
@@ -85,6 +85,12 @@ class ExternModifier : public Modifier
};
FIDDLE()
+class DynModifier : public Modifier
+{
+ FIDDLE(...)
+};
+
+FIDDLE()
class HLSLExportModifier : public Modifier
{
FIDDLE(...)
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index daa761d3d..c03d8e985 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -23,6 +23,176 @@
namespace Slang
{
+
+static bool isAssociatedTypeDecl(Decl* decl)
+{
+ auto d = decl;
+ while (auto genericDecl = as<GenericDecl>(d))
+ d = genericDecl->inner;
+ if (as<AssocTypeDecl>(d))
+ return true;
+ return false;
+}
+
+static bool isSlang2026(CompilerOptionSet& optionSet)
+{
+ if (!optionSet.hasOption(CompilerOptionName::Language))
+ return false;
+ return SLANG_SOURCE_LANGUAGE_SLANG ==
+ SlangSourceLanguage(
+ optionSet.getEnumOption<SlangSourceLanguage>(CompilerOptionName::Language)) &&
+ SLANG_STD_REVISION_2026 ==
+ optionSet.getEnumOption<SlangStdRevision>(CompilerOptionName::StdRevision);
+}
+
+static bool allowExperimentalDynamicDispatch(CompilerOptionSet& optionSet)
+{
+ return optionSet.getBoolOption(CompilerOptionName::EnableExperimentalDynamicDispatch) ||
+ !isSlang2026(optionSet);
+}
+
+static void validateDynInterfaceUsage(
+ SemanticsDeclVisitorBase* visitor,
+ DiagnosticSink* sink,
+ CompilerOptionSet& optionSet,
+ InterfaceDecl* decl)
+{
+ if (allowExperimentalDynamicDispatch(optionSet))
+ return;
+
+ if (!decl->hasModifier<DynModifier>())
+ return;
+
+ // validate members inside `dyn interface`
+ for (auto m : decl->members)
+ {
+ if (isAssociatedTypeDecl(m))
+ {
+ sink->diagnose(m, Diagnostics::cannotHaveAssociatedTypeInDynInterface);
+ continue;
+ }
+ else if (auto genericDecl = as<GenericDecl>(m))
+ {
+ if (as<FuncDecl>(genericDecl->inner))
+ {
+ sink->diagnose(m, Diagnostics::cannotHaveGenericMethodInDynInterface);
+ }
+ continue;
+ }
+ else if (auto funcDecl = as<FuncDecl>(m))
+ {
+ visitor->ensureDecl(m, DeclCheckState::ModifiersChecked);
+ for (auto modifier : funcDecl->modifiers)
+ {
+ if (as<MutatingAttribute>(modifier))
+ {
+ sink->diagnose(m, Diagnostics::cannotHaveMutatingMethodInDynInterface);
+ }
+ else if (as<DifferentiableAttribute>(modifier))
+ {
+ sink->diagnose(m, Diagnostics::cannotHaveDifferentiableMethodInDynInterface);
+ }
+ }
+ continue;
+ }
+ else if (auto inheritanceDecl = as<InheritanceDecl>(m))
+ {
+ visitor->ensureDecl(m, DeclCheckState::ReadyForLookup);
+ auto inheritedInterfaceDeclRefType =
+ isDeclRefTypeOf<InterfaceDecl>(inheritanceDecl->base.type);
+ if (!inheritedInterfaceDeclRefType)
+ continue;
+
+ auto inheritedInterfaceDecl = inheritedInterfaceDeclRefType.getDecl();
+ if (!inheritedInterfaceDecl->hasModifier<DynModifier>())
+ sink->diagnose(
+ m,
+ Diagnostics::DynInterfaceCannotInheritNonDynInterface,
+ decl,
+ inheritedInterfaceDecl);
+ }
+ }
+
+ // dyn interface cannot be generic
+ if (visitor->GetOuterGeneric(decl))
+ {
+ sink->diagnose(decl, Diagnostics::cannotHaveGenericDynInterface, decl);
+ }
+}
+
+static void validateDynInterfaceUseWithInheritanceDecl(
+ SemanticsDeclVisitorBase* visitor,
+ DiagnosticSink* sink,
+ CompilerOptionSet& optionSet,
+ InheritanceDecl* decl)
+{
+ auto interfaceDeclRef = isDeclRefTypeOf<InterfaceDecl>(decl->base.type);
+ if (!interfaceDeclRef)
+ return;
+ auto interfaceDecl = interfaceDeclRef.getDecl();
+ bool interfaceDeclIsDyn = interfaceDecl->hasModifier<DynModifier>();
+ if (!interfaceDeclIsDyn)
+ return;
+
+ if (!allowExperimentalDynamicDispatch(optionSet))
+ {
+ if (auto extensionDeclParent = as<ExtensionDecl>(decl->parentDecl))
+ {
+ // not allowed to extend to conform to a 'dyn interface'
+ sink->diagnose(
+ extensionDeclParent,
+ Diagnostics::cannotUseExtensionToMakeTypeConformToDynInterface,
+ interfaceDecl);
+ }
+ else if (visitor->GetOuterGeneric(decl->parentDecl))
+ {
+ sink->diagnose(
+ decl,
+ Diagnostics::cannotConformGenericToDynInterface,
+ decl->parentDecl,
+ interfaceDecl);
+ }
+ }
+ if (auto aggTypeDeclParent = as<AggTypeDecl>(decl->parentDecl))
+ {
+ // Ensure if we inherit from a `dyn interface` that the parent does not have: opaque
+ // types, unsized types, non-copyable types
+ for (auto m : aggTypeDeclParent->members)
+ {
+ auto varDecl = as<VarDecl>(m);
+ if (!varDecl)
+ continue;
+
+ visitor->ensureDecl(varDecl, DeclCheckState::ReadyForLookup);
+
+ if (isNonCopyableType(varDecl->getType()))
+ {
+ sink->diagnose(
+ m,
+ Diagnostics::cannotHaveNonCopyableMemberWhenInheritingDynInterface,
+ m,
+ interfaceDecl);
+ }
+
+ int varTypeTags = (int)visitor->getTypeTags(varDecl->getType());
+ bool isUnsized = varTypeTags & (int)TypeTag::Unsized;
+ bool isOpaque = varTypeTags & (int)TypeTag::Opaque;
+ if (isUnsized)
+ sink->diagnose(
+ m,
+ Diagnostics::cannotHaveUnsizedMemberWhenInheritingDynInterface,
+ m,
+ interfaceDecl);
+ if (isOpaque)
+ sink->diagnose(
+ m,
+ Diagnostics::cannotHaveOpaqueMemberWhenInheritingDynInterface,
+ m,
+ interfaceDecl);
+ }
+ }
+}
+
static ConstructorDecl* _getDefaultCtor(StructDecl* structDecl);
static List<ConstructorDecl*> _getCtorList(
ASTBuilder* m_astBuilder,
@@ -70,6 +240,8 @@ struct SemanticsDeclModifiersVisitor : public SemanticsDeclVisitorBase,
void visitDecl(Decl* decl) { checkModifiers(decl); }
void visitStructDecl(StructDecl* structDecl);
+
+ void visitInterfaceDecl(InterfaceDecl* interfaceDecl);
};
struct SemanticsDeclScopeWiringVisitor : public SemanticsDeclVisitorBase,
@@ -1485,6 +1657,16 @@ IntVal* SemanticsVisitor::_validateCircularVarDefinition(VarDeclBase* varDecl)
nullptr);
}
+void SemanticsDeclModifiersVisitor::visitInterfaceDecl(InterfaceDecl* interfaceDecl)
+{
+ visitDecl(interfaceDecl);
+
+ if (interfaceDecl->hasModifier<AnyValueSizeAttribute>())
+ addModifier(interfaceDecl, m_astBuilder->create<DynModifier>());
+
+ validateDynInterfaceUsage(this, getSink(), getOptionSet(), interfaceDecl);
+}
+
void SemanticsDeclModifiersVisitor::visitStructDecl(StructDecl* structDecl)
{
checkModifiers(structDecl);
@@ -3114,6 +3296,12 @@ struct SemanticsDeclDifferentialConformanceVisitor
void visitInheritanceDecl(InheritanceDecl* inheritanceDecl)
{
+ validateDynInterfaceUseWithInheritanceDecl(
+ this,
+ getSink(),
+ getOptionSet(),
+ inheritanceDecl);
+
if (as<InterfaceDecl>(inheritanceDecl->parentDecl))
return;
@@ -6964,16 +7152,6 @@ RefPtr<WitnessTable> SemanticsVisitor::checkInterfaceConformance(
return witnessTable;
}
-static bool isAssociatedTypeDecl(Decl* decl)
-{
- auto d = decl;
- while (auto genericDecl = as<GenericDecl>(d))
- d = genericDecl->inner;
- if (as<AssocTypeDecl>(d))
- return true;
- return false;
-}
-
bool SemanticsVisitor::checkInterfaceConformance(
ConformanceCheckingContext* context,
Type* subType,
diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp
index f9ad3a02f..900f503db 100644
--- a/source/slang/slang-check-modifier.cpp
+++ b/source/slang/slang-check-modifier.cpp
@@ -1532,6 +1532,8 @@ bool isModifierAllowedOnDecl(bool isGLSLInput, ASTNodeType modifierType, Decl* d
if (!as<VarDeclBase>(decl))
return false;
return isGlobalDecl(decl) || isEffectivelyStatic(decl);
+ case ASTNodeType::DynModifier:
+ return as<InterfaceDecl>(decl) || as<VarDecl>(decl) || as<ParamDecl>(decl);
default:
return true;
}
@@ -1671,6 +1673,7 @@ Modifier* SemanticsVisitor::checkModifier(
{
auto moduleDecl = getModuleDecl(decl);
bool isGLSLInput = getOptionSet().getBoolOption(CompilerOptionName::AllowGLSL);
+
if (!isGLSLInput && moduleDecl && moduleDecl->findModifier<GLSLModuleModifier>())
isGLSLInput = true;
if (!isModifierAllowedOnDecl(isGLSLInput, m->astNodeType, decl))
diff --git a/source/slang/slang-compiler-options.cpp b/source/slang/slang-compiler-options.cpp
index ca8397f3e..0d7f19642 100644
--- a/source/slang/slang-compiler-options.cpp
+++ b/source/slang/slang-compiler-options.cpp
@@ -208,6 +208,8 @@ CompilerOptionValue Slang::CompilerOptionSet::getDefault(CompilerOptionName name
{
case CompilerOptionName::Optimization:
return CompilerOptionValue::fromEnum(OptimizationLevel::Default);
+ case CompilerOptionName::StdRevision:
+ return CompilerOptionValue::fromEnum(SlangStdRevision::SLANG_STD_REVISION_DEFAULT);
default:
return CompilerOptionValue();
}
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index cafd61062..bf90c6608 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -146,6 +146,9 @@ DIAGNOSTIC(
entryPointsNeedToBeAssociatedWithTranslationUnits,
"when using multiple source files, entry points must be specified after their corresponding "
"source file(s)")
+
+DIAGNOSTIC(21, Error, unknownStdRevision, "unknown language standard revision '$0'")
+
DIAGNOSTIC(22, Error, unknownDownstreamCompiler, "unknown downstream compiler '$0'")
DIAGNOSTIC(26, Error, unknownOptimiziationLevel, "unknown optimization level '$0'")
@@ -827,6 +830,59 @@ DIAGNOSTIC(
DIAGNOSTIC(33070, Error, expectedFunction, "expected a function, got '$0'")
DIAGNOSTIC(33071, Error, expectedAStringLiteral, "expected a string literal")
+// `dyn` and `some` errors
+DIAGNOSTIC(33072, Error, cannotHaveGenericDynInterface, "dyn interfaces cannot be generic: '$0'.")
+DIAGNOSTIC(
+ 33073,
+ Error,
+ cannotHaveAssociatedTypeInDynInterface,
+ "dyn interfaces cannot have associatedType members.")
+DIAGNOSTIC(
+ 33074,
+ Error,
+ cannotHaveGenericMethodInDynInterface,
+ "dyn interfaces cannot have generic methods.")
+DIAGNOSTIC(
+ 33075,
+ Error,
+ cannotHaveMutatingMethodInDynInterface,
+ "dyn interfaces cannot have [mutating] methods.")
+DIAGNOSTIC(
+ 33076,
+ Error,
+ cannotHaveDifferentiableMethodInDynInterface,
+ "dyn interfaces cannot have [Differentiable] methods.")
+DIAGNOSTIC(
+ 33077,
+ Error,
+ DynInterfaceCannotInheritNonDynInterface,
+ "dyn interface '$0' may only inherit 'dyn' interfaces. '$1' is not a dyn interface.")
+DIAGNOSTIC(
+ 33078,
+ Error,
+ cannotUseExtensionToMakeTypeConformToDynInterface,
+ "cannot use a extension to conform to a dyn interface '$0'.")
+DIAGNOSTIC(
+ 33079,
+ Error,
+ cannotHaveUnsizedMemberWhenInheritingDynInterface,
+ "cannot have unsized member '$0' when inheriting from dyn interface '$1'.")
+DIAGNOSTIC(
+ 33080,
+ Error,
+ cannotHaveOpaqueMemberWhenInheritingDynInterface,
+ "cannot have opaque member '$0' when inheriting from dyn interface '$1'.")
+DIAGNOSTIC(
+ 33081,
+ Error,
+ cannotHaveNonCopyableMemberWhenInheritingDynInterface,
+ "cannot have non-copyable member '$0' when inheriting from dyn interface '$1'.")
+DIAGNOSTIC(
+ 33082,
+ Error,
+ cannotConformGenericToDynInterface,
+ "cannot conform generic type '$0' to dyn interface '$1'.")
+
DIAGNOSTIC(
-1,
Note,
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index d73bc4307..0182b4c22 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -63,6 +63,7 @@ enum class ValueCategory
FileSystemType,
VulkanShift,
SourceEmbedStyle,
+ StdRevision,
CountOf,
};
@@ -149,6 +150,14 @@ void initCommandOptions(CommandOptions& options)
options.addCategory(
CategoryKind::Value,
+ "std-revision",
+ "Std Revision",
+ UserValue(ValueCategory::StdRevision));
+ options.addValues(TypeTextUtil::getStdRevisionInfos());
+
+
+ options.addCategory(
+ CategoryKind::Value,
"archive-type",
"Archive Type",
UserValue(ValueCategory::ArchiveType));
@@ -446,6 +455,10 @@ void initCommandOptions(CommandOptions& options)
"Display the build version. This is the contents of git describe --tags.\n"
"It is typically only set from automated builds(such as distros available on github).A "
"user build will by default be 'unknown'."},
+ {OptionKind::StdRevision,
+ "-std",
+ "-std <std-revision>",
+ "Specifies the language standard that should be used."},
{OptionKind::WarningsAsErrors,
"-warnings-as-errors",
"-warnings-as-errors all or -warnings-as-errors <id>[,<id>...]",
@@ -841,6 +854,10 @@ void initCommandOptions(CommandOptions& options)
"-enable-experimental-passes",
nullptr,
"Enable experimental compiler passes"},
+ {OptionKind::EnableExperimentalDynamicDispatch,
+ "-enable-experimental-dynamic-dispatch",
+ nullptr,
+ "Enable experimental dynamic dispatch features"},
{OptionKind::EmbedDownstreamIR,
"-embed-downstream-ir",
nullptr,
@@ -2146,6 +2163,7 @@ SlangResult OptionsParser::_parse(int argc, char const* const* argv)
case OptionKind::ValidateUniformity:
case OptionKind::AllowGLSL:
case OptionKind::EnableExperimentalPasses:
+ case OptionKind::EnableExperimentalDynamicDispatch:
case OptionKind::EmitIr:
case OptionKind::DumpIntermediates:
case OptionKind::DumpReproOnError:
@@ -2537,6 +2555,24 @@ SlangResult OptionsParser::_parse(int argc, char const* const* argv)
}
break;
}
+ case OptionKind::StdRevision:
+ {
+ CommandLineArg name;
+ SLANG_RETURN_ON_FAIL(m_reader.expectArg(name));
+
+ SlangStdRevision stdRevision =
+ TypeTextUtil::findStdRevision(name.value.getUnownedSlice());
+ if (stdRevision == SLANG_STD_REVISION_UNKNOWN)
+ {
+ m_sink->diagnose(name.loc, Diagnostics::unknownStdRevision, name.value);
+ return SLANG_FAIL;
+ }
+ else
+ {
+ linkage->m_optionSet.add(OptionKind::StdRevision, stdRevision);
+ }
+ break;
+ }
case OptionKind::Stage:
{
CommandLineArg name;
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 7ff0a6a2f..b2a006adc 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -9159,6 +9159,8 @@ static const SyntaxParseInfo g_parseSyntaxEntries[] = {
_makeParseModifier("param", getSyntaxClass<ParamModifier>()),
_makeParseModifier("extern", getSyntaxClass<ExternModifier>()),
+ _makeParseModifier("dyn", getSyntaxClass<DynModifier>()),
+
_makeParseModifier("row_major", getSyntaxClass<HLSLRowMajorLayoutModifier>()),
_makeParseModifier("column_major", getSyntaxClass<HLSLColumnMajorLayoutModifier>()),
diff --git a/tests/compute/dynamic-dispatch-bindless-texture.slang b/tests/compute/dynamic-dispatch-bindless-texture.slang
index b02ca9686..ec21afeda 100644
--- a/tests/compute/dynamic-dispatch-bindless-texture.slang
+++ b/tests/compute/dynamic-dispatch-bindless-texture.slang
@@ -2,37 +2,29 @@
//TEST(compute):COMPARE_COMPUTE:-cpu
//TEST(compute):COMPARE_COMPUTE:-cuda
-[anyValueSize(16)]
-interface IInterface
+// Type must be marked `public` to ensure it is visible in the generated DLL.
+
+export struct MyImpl
{
- float run();
-}
+ Texture2D tex;
+ float run()
+ {
+ return tex.Load({0, 0, 0}).x;
+ }
+};
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=gOutputBuffer
RWStructuredBuffer<uint> gOutputBuffer;
-//TEST_INPUT: set gCb = new StructuredBuffer<IInterface>{new MyImpl{Texture2D(size=8, content = one), Sampler}}
-StructuredBuffer<IInterface> gCb;
+//TEST_INPUT: set gCb = new StructuredBuffer<MyImpl>{new MyImpl{Texture2D(size=8, content = one)}}
+StructuredBuffer<MyImpl> gCb;
[numthreads(4, 1, 1)]
-void computeMain(int3 dispatchThreadID : SV_DispatchThreadID)
+void computeMain(int3 dispatchThreadID : SV_DispatchThreadID)
{
let tid = dispatchThreadID.x;
let inputVal : int = tid;
- IInterface v0 = gCb.Load(0);
- SamplerState sampler;
+ MyImpl v0 = gCb.Load(0);
let outputVal = v0.run();
gOutputBuffer[tid] = uint(trunc(outputVal));
-}
-
-
-// Type must be marked `public` to ensure it is visible in the generated DLL.
-export struct MyImpl : IInterface
-{
- Texture2D tex;
- SamplerState sampler;
- float run()
- {
- return tex.Sample(sampler, float2(0.0, 0.0)).x;
- }
-};
+} \ No newline at end of file
diff --git a/tests/compute/interface-qualifiers/dyn-on-type-uses.slang b/tests/compute/interface-qualifiers/dyn-on-type-uses.slang
new file mode 100644
index 000000000..16e9e6efa
--- /dev/null
+++ b/tests/compute/interface-qualifiers/dyn-on-type-uses.slang
@@ -0,0 +1,186 @@
+//TEST:SIMPLE(filecheck=CHECK_2026): -target spirv -stage compute -entry computeMain -lang slang -std 2026
+//TEST:SIMPLE(filecheck=CHECK_2025_OR_EXP): -target spirv -stage compute -entry computeMain
+//TEST:SIMPLE(filecheck=CHECK_2025_OR_EXP): -target spirv -stage compute -entry computeMain -lang slang -std 2026 -enable-experimental-dynamic-dispatch
+
+// Validate AST side of `dyn` keyword use-cases
+
+// `experimental-dynamic-dispatch` and `-lang 2025` have fewer restrictions
+//
+// CHECK_2025_OR_EXP-NOT: error 33072
+// CHECK_2025_OR_EXP-NOT: error 33073
+// CHECK_2025_OR_EXP-NOT: error 33074
+// CHECK_2025_OR_EXP-NOT: error 33075
+// CHECK_2025_OR_EXP-NOT: error 33076
+// CHECK_2025_OR_EXP-NOT: error 33077
+// CHECK_2025_OR_EXP-NOT: error 33078
+// CHECK_2025_OR_EXP-NOT: error 33082
+
+/////////////////////////////////////////////////////
+
+// `dyn` interfaces are not allowed to be generics
+// CHECK_2026-DAG: error 33072
+dyn interface interface1<T>
+{
+ static const int member;
+};
+
+// `dyn` interfaces must not define any associated types.
+// CHECK_2026-DAG: error 33073
+interface IBase1
+{
+};
+dyn interface interface2
+{
+ associatedtype IBase1;
+};
+
+// `dyn` interfaces must not define any generic methods.
+// CHECK_2026-DAG: error 33074
+dyn interface interface3
+{
+ T genericFunc<T : IArithmetic>(T val)
+ {
+ return val*(T)2;
+ }
+};
+
+// `dyn` interfaces must not define any mutating methods
+// CHECK_2026-DAG: error 33075
+dyn interface interface4
+{
+ [mutating]
+ void mutate(int val);
+};
+
+// `dyn` interfaces cannot inherit from any interfaces that are not dyn.
+// CHECK_2026-DAG: error 33077
+
+interface IBase2
+{
+};
+
+dyn interface interface5 : IBase2
+{
+ int myFunc(int val)
+ {
+ return val*2;
+ }
+};
+
+dyn interface IBase3
+{
+};
+
+dyn interface interface6 : IBase3
+{
+ int myFunc(int val)
+ {
+ return val*2;
+ }
+};
+
+// `dyn` interfaces cannot contain any function requirements that are marked as [Differentiable].
+// CHECK_2026-DAG: error 33076
+dyn interface interface7
+{
+ [Differentiable]
+ int myFunc(int val)
+ {
+ return val*2;
+ }
+};
+
+// The type which is conforming to a dyn (myType in interface myType : IBase) cannot be generic.
+// CHECK_2026-DAG: error 33082
+// CHECK_2026-DAG: error 33082
+dyn interface IBase4
+{
+ int doMath(int val);
+};
+
+struct genericStruct1<T : IArithmetic> : IBase4
+{
+ T a;
+ int doMath(int v)
+ {
+ return v * (int)2;
+ }
+};
+
+interface genericInterface1<T : IArithmetic> : IBase4
+{
+ T doMath(T v)
+ {
+ return v * (T)3;
+ }
+};
+
+// Extensions that make a type conform/inherit to dyn interfaces are not allowed.
+// CHECK_2026-DAG: error 33078
+dyn interface IBase5
+{
+};
+interface interface9
+{
+};
+
+extension<T:interface9> T : IBase5
+{
+ int doMath()
+ {
+ return 5;
+ }
+};
+
+// Type conforming to `dyn` interface must be an ordinary data type, meaning that it cannot contain any fields that are opaque or non-copyable or unsized.
+// CHECK_2026-DAG: error 33079
+// CHECK_2026-DAG: error 33080
+// CHECK_2026-DAG: error 33081
+// CHECK_2026-DAG: error 33081
+
+// CHECK_2025_OR_EXP-DAG: error 33079
+// CHECK_2025_OR_EXP-DAG: error 33080
+// CHECK_2025_OR_EXP-DAG: error 33081
+
+struct structWithUnsized : IBase6
+{
+ int v[];
+};
+
+struct structWithOpaque : IBase6
+{
+ Texture2D<float> v;
+};
+
+dyn interface IBase6
+{
+};
+[__NonCopyableType]
+struct NonCopyableStruct1
+{
+ float v;
+}
+struct structWithNonCopyable1 : IBase6
+{
+ NonCopyableStruct1 v;
+};
+[__NonCopyableType]
+struct NonCopyableStruct2<T : IArithmetic>
+{
+ T v;
+}
+struct structWithNonCopyable2 : IBase6
+{
+ NonCopyableStruct2<int> v;
+};
+
+// `dyn` interfaces cannot contain any methods that has a `some` IFoo return type, or has any `some` IFoo parameters.
+// TODO-INTERFACE-QUALIFIERS-ADDITION-OF-SOME
+//
+
+RWStructuredBuffer<int> outputBuffer;
+[numthreads(4, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ outputBuffer[0] = 0;
+}
diff --git a/tests/compute/interface-qualifiers/some-and-dyn-vardecl-uses.slang b/tests/compute/interface-qualifiers/some-and-dyn-vardecl-uses.slang
new file mode 100644
index 000000000..4caa3ec56
--- /dev/null
+++ b/tests/compute/interface-qualifiers/some-and-dyn-vardecl-uses.slang
@@ -0,0 +1 @@
+// TODO-INTERFACE-QUALIFIERS-ADDITION-OF-SOME \ No newline at end of file