diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/core/slang-type-text-util.cpp | 16 | ||||
| -rw-r--r-- | source/core/slang-type-text-util.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-ast-modifier.h | 6 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 198 | ||||
| -rw-r--r-- | source/slang/slang-check-modifier.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang-compiler-options.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 56 | ||||
| -rw-r--r-- | source/slang/slang-options.cpp | 36 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 2 |
9 files changed, 314 insertions, 10 deletions
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>()), |
