summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaizhangNV <149626564+kaizhangNV@users.noreply.github.com>2025-02-05 12:37:03 -0600
committerGitHub <noreply@github.com>2025-02-05 10:37:03 -0800
commit9ec6b91686b651d959fd9ffbec283845bd725dd6 (patch)
tree2c48202cb04b76e5ddcb274be35529378ddf8f31
parent4b350645042b8e8fbdad19784ee745d11c7bc616 (diff)
Feature/initialize list side branch (#6058)
* SP004: implement initialize list translation to ctor - We synthesize a member-wise constructor for each struct follow the rules described in SP004. - Add logic to translate the initialize list to constructor invoke - Add cuda-host decoration for the synthesized constructor - Remove the default constructor when we have a valid member init constructor - Disable -zero-initialize option, will re-implement it in followup (#6109). - Fix the overload lookup issue When creating invoke expression for ctor, we need to call ResolveInvoke() to find us the best candidates, however the existing lookup logic could find us the base constructor for child struct, we should eliminate this case by providing the LookupOptions::IgnoreInheritance to lookup, this requires us to create a subcontext on SemanticsVisitor to indicate that we only want to use this option on looking the constructor. - Do not implicit initialize a struct that doesn't have explicit default constructor. Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
-rw-r--r--.github/workflows/falcor-test.yml12
-rw-r--r--CMakeLists.txt3
-rw-r--r--docs/proposals/004-initialization.md38
-rw-r--r--source/slang/core.meta.slang2
-rw-r--r--source/slang/hlsl.meta.slang23
-rw-r--r--source/slang/slang-ast-decl.h21
-rw-r--r--source/slang/slang-ast-expr.h7
-rw-r--r--source/slang/slang-check-conversion.cpp243
-rw-r--r--source/slang/slang-check-decl.cpp540
-rw-r--r--source/slang/slang-check-expr.cpp4
-rw-r--r--source/slang/slang-check-impl.h28
-rw-r--r--source/slang/slang-check-overload.cpp19
-rw-r--r--source/slang/slang-ir-check-differentiability.cpp12
-rw-r--r--source/slang/slang-lower-to-ir.cpp5
-rw-r--r--source/slang/slang-options.cpp15
-rw-r--r--tests/autodiff/differential-type-constructor.slang6
-rw-r--r--tests/autodiff/generic-constructor.slang10
-rw-r--r--tests/autodiff/generic-impl-jvp.slang26
-rw-r--r--tests/autodiff/self-differential-generic-type-synthesis.slang2
-rw-r--r--tests/autodiff/self-differential-type-synthesis.slang2
-rw-r--r--tests/bugs/addr-scope-fix.slang3
-rw-r--r--tests/bugs/generic-default-value.slang7
-rw-r--r--tests/bugs/gh-4863.slang4
-rw-r--r--tests/bugs/overload-ambiguous-2.slang2
-rw-r--r--tests/compute/empty-struct2.slang2
-rw-r--r--tests/compute/struct-default-init.slang1
-rw-r--r--tests/compute/type-legalize-global-with-init.slang1
-rw-r--r--tests/cpu-program/gfx-smoke.slang8
-rw-r--r--tests/diagnostics/interfaces/anyvalue-size-validation.slang2
-rw-r--r--tests/diagnostics/mismatching-types.slang9
-rw-r--r--tests/diagnostics/mismatching-types.slang.expected21
-rw-r--r--tests/diagnostics/uninitialized-fields.slang4
-rw-r--r--tests/diagnostics/variable-redeclaration.slang2
-rw-r--r--tests/diagnostics/variable-redeclaration.slang.expected24
-rw-r--r--tests/initializer-list/c-style-type.slang44
-rw-r--r--tests/initializer-list/default-member.slang35
-rw-r--r--tests/initializer-list/explicit-ctor-diagnostic.slang19
-rw-r--r--tests/initializer-list/explicit-ctor.slang41
-rw-r--r--tests/initializer-list/extension-overload-1.slang49
-rw-r--r--tests/initializer-list/extension-overload-2.slang28
-rw-r--r--tests/initializer-list/modulea.slang5
-rw-r--r--tests/initializer-list/partial-init-diagnostic.slang19
-rw-r--r--tests/initializer-list/partial-init.slang47
-rw-r--r--tests/initializer-list/struct-visibility-1.slang105
-rw-r--r--tests/initializer-list/struct-visibility-diagnostic-1.slang21
-rw-r--r--tests/initializer-list/struct-visibility-diagnostic-2.slang21
-rw-r--r--tests/initializer-list/struct-visibility-diagnostic-3.slang21
-rw-r--r--tests/initializer-list/struct-visibility-diagnostic-4.slang16
-rw-r--r--tests/initializer-list/unintialize-warning.slang85
-rw-r--r--tests/language-feature/extensions/interface-extension.slang1
-rw-r--r--tests/language-feature/extensions/this-in-extension.slang3
-rw-r--r--tests/language-feature/generics/struct-generic-value-param.slang1
-rw-r--r--tests/language-feature/inheritance/derived-struct-init-list.slang1
-rw-r--r--tests/language-feature/inheritance/struct-inherit-interface-requirement.slang1
-rw-r--r--tests/language-feature/inheritance/struct-inheritance.slang1
-rw-r--r--tests/language-feature/initializer-lists/inheritance-generic.slang5
-rw-r--r--tests/language-feature/interfaces/zero-init-interface.slang1
-rw-r--r--tests/language-feature/overloaded-subscript.slang2
-rw-r--r--tests/language-feature/properties/property-in-interface.slang2
-rw-r--r--tests/language-feature/struct-field-initializers/struct-field-initializer-import.slang6
-rw-r--r--tests/language-feature/struct-field-initializers/struct-field-initializer-inherited-chain.slang10
-rw-r--r--tests/language-feature/struct-field-initializers/struct-field-initializer-inherited.slang6
-rw-r--r--tests/language-feature/struct-field-initializers/struct-field-initializer-static.slang4
-rw-r--r--tests/language-feature/types/is-on-type.slang3
-rw-r--r--tests/language-feature/zero-initialize/IDefaultExplicit-wrapper-type.slang10
-rw-r--r--tests/language-feature/zero-initialize/IDefaultExplicit.slang10
-rw-r--r--tests/language-feature/zero-initialize/IDefaultExplicitGenerics.slang10
-rw-r--r--tests/language-feature/zero-initialize/generic.slang8
-rw-r--r--tests/language-feature/zero-initialize/missing-zero-init.slang4
-rw-r--r--tests/language-feature/zero-initialize/rayquery.slang4
-rw-r--r--tests/language-feature/zero-initialize/regular.slang8
-rw-r--r--tests/language-feature/zero-initialize/shared-memory.slang4
-rw-r--r--tests/language-feature/zero-initialize/static-struct-field-init-list.slang2
-rw-r--r--tests/language-feature/zero-initialize/static-struct-field-init.slang4
-rw-r--r--tests/language-feature/zero-initialize/struct-array-some-member-missing-init.slang4
-rw-r--r--tests/language-feature/zero-initialize/struct-array.slang8
-rw-r--r--tests/language-feature/zero-initialize/struct-no-zero-init.slang4
-rw-r--r--tests/language-feature/zero-initialize/struct-some-member-init-missing-zero-init.slang4
-rw-r--r--tests/language-feature/zero-initialize/struct-some-zero-init.slang10
-rw-r--r--tests/language-feature/zero-initialize/struct.slang8
-rw-r--r--tests/pipeline/rasterization/mesh/hlsl-syntax.slang.glsl34
-rw-r--r--tests/pipeline/ray-tracing/trace-ray-inline.slang.hlsl93
-rw-r--r--tests/spirv/debug-type-pointer.slang2
-rw-r--r--tools/gfx/gfx.slang53
-rw-r--r--tools/slang-unit-test/unit-test-decl-tree-reflection.cpp4
85 files changed, 1719 insertions, 280 deletions
diff --git a/.github/workflows/falcor-test.yml b/.github/workflows/falcor-test.yml
index ff9f2fb70..91a6c9ea5 100644
--- a/.github/workflows/falcor-test.yml
+++ b/.github/workflows/falcor-test.yml
@@ -59,12 +59,12 @@ jobs:
run: |
mkdir FalcorBin
cd FalcorBin
- Copy-Item -Path 'C:\Falcor\build\windows-vs2022\bin' -Destination '.\build\windows-vs2022\bin' -Recurse -Exclude ("*.pdb")
- Copy-Item -Path 'C:\Falcor\tests' -Destination '.\' -Recurse
- Copy-Item -Path 'C:\Falcor\tools' -Destination '.\' -Recurse
- Copy-Item -Path 'C:\Falcor\media' -Destination '.\' -Recurse
- Copy-Item -Path 'C:\Falcor\media_internal' -Destination '.\' -Recurse
- Copy-Item -Path 'C:\Falcor\scripts' -Destination '.\' -Recurse
+ Copy-Item -Path 'C:\Falcor-new\build\windows-vs2022\bin' -Destination '.\build\windows-vs2022\bin' -Recurse -Exclude ("*.pdb")
+ Copy-Item -Path 'C:\Falcor-new\tests' -Destination '.\' -Recurse
+ Copy-Item -Path 'C:\Falcor-new\tools' -Destination '.\' -Recurse
+ Copy-Item -Path 'C:\Falcor-new\media' -Destination '.\' -Recurse
+ Copy-Item -Path 'C:\Falcor-new\media_internal' -Destination '.\' -Recurse
+ Copy-Item -Path 'C:\Falcor-new\scripts' -Destination '.\' -Recurse
cd ..\
- name: Build Slang
run: |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index df06300d8..48d263d14 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,6 +33,9 @@ cmake_policy(SET CMP0091 NEW)
# tree relocatable
set(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE)
+# Export the compile datebase as a json file, this can be used by VIM language server
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
# Enable placing targets into a hierarchy for IDE generators
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
diff --git a/docs/proposals/004-initialization.md b/docs/proposals/004-initialization.md
index 6a41cab23..9ce143866 100644
--- a/docs/proposals/004-initialization.md
+++ b/docs/proposals/004-initialization.md
@@ -129,6 +129,39 @@ MyType x = MyType(y); // equivalent to `x = y`.
The compiler will attempt to resolve all type casts using type coercion rules, if that failed, will fall back to resolve it as a constructor call.
+### Inheritance Initialization
+For derived structs, slang will synthesized the constructor by bringing the parameters from the base struct's constructor if the base struct also has a synthesized constructor. For example:
+```csharp
+struct Base
+{
+ int x;
+ // compiler synthesizes:
+ // __init(int x) { ... }
+}
+struct Derived : Base
+{
+ int y;
+ // compiler synthesizes:
+ // __init(int x, int y) { ... }
+}
+```
+
+However, if the base struct has explicit ctors, the compiler will not synthesize a constructor for the derived struct.
+For example, given
+```csharp
+struct Base { int x; __init(int x) { this.x = x; } }
+struct Derived : Base { int y;}
+```
+The compiler will not synthesize a constructor for `Derived`, and the following code will fail to compile:
+```csharp
+
+Derived d = {1}; // error, no matching ctor.
+Derived d = {1, 2}; // error, no matching ctor.
+Derived d = Derived(1); // error, no matching ctor.
+Derived d = Derived(1, 2); // error, no matching ctor.
+```
+
+
### Initialization List
Slang allows initialization of a variable by assigning it with an initialization list.
@@ -167,7 +200,8 @@ If the above code passes type check, then it will be used as the way to initiali
If the above code does not pass type check, and if there is only one constructor for`MyType` that is synthesized as described in the previous section (and therefore marked as `[Synthesized]`, Slang continues to check if `S` meets the standard of a "legacy C-style struct` type.
A type is a "legacy C-Style struct" if all of the following conditions are met:
-- It is a user-defined struct type or a basic scalar, vector or matrix type, e.g. `int`, `float4x4`.
+- It is a user-defined struct type or an enum, a basic scalar, vector or matrix type, e.g. `int`, `float4x4`.
+- It does not inherit from any other types.
- It does not contain any explicit constructors defined by the user.
- All its members have the same visibility as the type itself.
- All its members are legacy C-Style structs or arrays of legacy C-style structs.
@@ -405,4 +439,4 @@ Alternatives Considered
One important decision point is whether or not Slang should allow variables to be left in uninitialized state after its declaration as it is allowed in C++. In contrast, C# forces everything to be default initialized at its declaration site, which come at the cost of incurring the burden to developers to come up with a way to define the default value for each type.
Our opinion is we want to allow things as uninitialized, and to have the compiler validation checks to inform
-the developer something is wrong if they try to use a variable in uninitialized state. We believe it is desirable to tell the developer what's wrong instead of using a heavyweight mechanism to ensure everything is initialized at declaration sites, which can have non-trivial performance consequences for GPU programs, especially when the variable is declared in groupshared memory. \ No newline at end of file
+the developer something is wrong if they try to use a variable in uninitialized state. We believe it is desirable to tell the developer what's wrong instead of using a heavyweight mechanism to ensure everything is initialized at declaration sites, which can have non-trivial performance consequences for GPU programs, especially when the variable is declared in groupshared memory.
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index 19421735c..b7f50cd1b 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -1749,6 +1749,8 @@ struct NativeString
__implicit_conversion($(kConversionCost_None))
__intrinsic_op($(kIROp_getNativeStr))
__init(String value);
+
+ __init() { this = NativeString(""); }
};
extension Ptr<void>
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index 3baad5c10..2399df254 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -21107,11 +21107,12 @@ ${
case hlsl:
uint isSingleLod = 0;
- Footprint footprint = {__queryFootprint$(CoarseOrFine)NVAPI(
+ __queryFootprint$(CoarseOrFine)NVAPI(
Shape.dimensions,
__getRegisterSpace(this), __getRegisterIndex(this),
__getRegisterSpace(sampler), __getRegisterIndex(sampler),
- __vectorReshape<3>(coords), granularity, /* out */isSingleLod), false};
+ __vectorReshape<3>(coords), granularity, /* out */isSingleLod);
+ Footprint footprint = {false};
footprint._isSingleLevel = (isSingleLod != 0);
return footprint;
}
@@ -21140,12 +21141,12 @@ ${
return footprint;
case hlsl:
uint isSingleLod = 0;
- Footprint footprint = {__queryFootprint$(CoarseOrFine)BiasNVAPI(
+ __queryFootprint$(CoarseOrFine)BiasNVAPI(
Shape.dimensions,
__getRegisterSpace(this), __getRegisterIndex(this),
__getRegisterSpace(sampler), __getRegisterIndex(sampler),
- __vectorReshape<3>(coords), granularity, lodBias, /* out */isSingleLod), false};
-
+ __vectorReshape<3>(coords), granularity, lodBias, /* out */isSingleLod);
+ Footprint footprint = {false};
footprint._isSingleLevel = (isSingleLod != 0);
return footprint;
}
@@ -21223,12 +21224,12 @@ ${
return footprint;
case hlsl:
uint isSingleLod = 0;
- Footprint footprint = {__queryFootprint$(CoarseOrFine)LevelNVAPI(
+ __queryFootprint$(CoarseOrFine)LevelNVAPI(
Shape.dimensions,
__getRegisterSpace(this), __getRegisterIndex(this),
__getRegisterSpace(sampler), __getRegisterIndex(sampler),
- __vectorReshape<3>(coords), granularity, lod, /* out */isSingleLod), false};
-
+ __vectorReshape<3>(coords), granularity, lod, /* out */isSingleLod);
+ Footprint footprint = {false};
footprint._isSingleLevel = (isSingleLod != 0);
return footprint;
}
@@ -21262,12 +21263,12 @@ ${{{
return footprint;
case hlsl:
uint isSingleLod = 0;
- Footprint footprint = {__queryFootprint$(CoarseOrFine)GradNVAPI(
+ __queryFootprint$(CoarseOrFine)GradNVAPI(
Shape.dimensions,
__getRegisterSpace(this), __getRegisterIndex(this),
__getRegisterSpace(sampler), __getRegisterIndex(sampler),
- __vectorReshape<3>(coords), granularity, __vectorReshape<3>(dx), __vectorReshape<3>(dy), /* out */isSingleLod), false};
-
+ __vectorReshape<3>(coords), granularity, __vectorReshape<3>(dx), __vectorReshape<3>(dy), /* out */isSingleLod);
+ Footprint footprint = {false};
footprint._isSingleLevel = (isSingleLod != 0);
return footprint;
}
diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h
index 7feb70e6a..ff8e5684a 100644
--- a/source/slang/slang-ast-decl.h
+++ b/source/slang/slang-ast-decl.h
@@ -165,6 +165,10 @@ class AggTypeDecl : public AggTypeDeclBase
class StructDecl : public AggTypeDecl
{
SLANG_AST_CLASS(StructDecl);
+
+ SLANG_UNREFLECTED
+ // We will use these auxiliary to help in synthesizing the member initialize constructor.
+ Slang::HashSet<VarDeclBase*> m_membersVisibleInCtor;
};
class ClassDecl : public AggTypeDecl
@@ -374,9 +378,20 @@ class ConstructorDecl : public FunctionDeclBase
{
SLANG_AST_CLASS(ConstructorDecl)
- // Indicates whether the declaration was synthesized by
- // slang and not actually provided by the user
- bool isSynthesized = false;
+ enum class ConstructorFlavor : int
+ {
+ UserDefined = 0x00,
+ // Indicates whether the declaration was synthesized by
+ // Slang and not explicitly provided by the user
+ SynthesizedDefault = 0x01,
+ // Member initialize constructor is a synthesized ctor,
+ // but it takes parameters.
+ SynthesizedMemberInit = 0x02
+ };
+
+ int m_flavor = (int)ConstructorFlavor::UserDefined;
+ void addFlavor(ConstructorFlavor flavor) { m_flavor |= (int)flavor; }
+ bool containsFlavor(ConstructorFlavor flavor) { return m_flavor & (int)flavor; }
};
// A subscript operation used to index instances of a type
diff --git a/source/slang/slang-ast-expr.h b/source/slang/slang-ast-expr.h
index 409909b16..c9bc86b79 100644
--- a/source/slang/slang-ast-expr.h
+++ b/source/slang/slang-ast-expr.h
@@ -135,6 +135,8 @@ class InitializerListExpr : public Expr
{
SLANG_AST_CLASS(InitializerListExpr)
List<Expr*> args;
+
+ bool useCStyleInitialization = true;
};
class GetArrayLengthExpr : public Expr
@@ -193,6 +195,11 @@ class InvokeExpr : public AppExprBase
SLANG_AST_CLASS(InvokeExpr)
};
+class ExplicitCtorInvokeExpr : public InvokeExpr
+{
+ SLANG_AST_CLASS(ExplicitCtorInvokeExpr)
+};
+
enum class TryClauseType
{
None,
diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp
index db8548dce..d89997bad 100644
--- a/source/slang/slang-check-conversion.cpp
+++ b/source/slang/slang-check-conversion.cpp
@@ -205,6 +205,234 @@ DeclRef<StructDecl> findBaseStructDeclRef(
return baseStructDeclRef;
}
+ConstructorDecl* SemanticsVisitor::_getSynthesizedConstructor(
+ StructDecl* structDecl,
+ ConstructorDecl::ConstructorFlavor flavor)
+{
+ for (auto ctor : structDecl->getMembersOfType<ConstructorDecl>())
+ {
+ if (ctor->containsFlavor(flavor))
+ return ctor;
+ }
+ return nullptr;
+}
+
+bool SemanticsVisitor::isCStyleType(Type* type, HashSet<Type*>& isVisit)
+{
+ isVisit.add(type);
+ auto cacheResult = [&](bool result)
+ {
+ getShared()->cacheCStyleType(type, result);
+ return result;
+ };
+
+ // Check cache first
+ if (bool* isCStyle = getShared()->isCStyleType(type))
+ {
+ return *isCStyle;
+ }
+
+ // 1. It has to be basic scalar, vector or matrix type, or user-defined struct.
+ if (as<VectorExpressionType>(type) || as<MatrixExpressionType>(type) ||
+ as<BasicExpressionType>(type) || isDeclRefTypeOf<EnumDecl>(type).getDecl())
+ return cacheResult(true);
+
+
+ if (auto structDecl = isDeclRefTypeOf<StructDecl>(type).getDecl())
+ {
+ // 2. It cannot have inheritance, but inherit from interface is fine.
+ for (auto inheritanceDecl : structDecl->getMembersOfType<InheritanceDecl>())
+ {
+ if (!isDeclRefTypeOf<InterfaceDecl>(inheritanceDecl->base.type))
+ {
+ return cacheResult(false);
+ }
+ }
+
+ // 3. It cannot have explicit constructor
+ if (_hasExplicitConstructor(structDecl, true))
+ return cacheResult(false);
+
+ // 4. All of its members have to have the same visibility as the struct itself.
+ DeclVisibility structVisibility = getDeclVisibility(structDecl);
+ for (auto varDecl : structDecl->getMembersOfType<VarDeclBase>())
+ {
+ if (getDeclVisibility(varDecl) != structVisibility)
+ {
+ return cacheResult(false);
+ }
+ }
+
+ for (auto varDecl : structDecl->getMembersOfType<VarDeclBase>())
+ {
+ Type* varType = varDecl->getType();
+
+ if (isDeclRefTypeOf<StructDecl>(varType))
+ {
+ // Avoid infinite loop in case of circular reference.
+ if (isVisit.contains(varType))
+ continue;
+ }
+
+ // Recursively check the type of the member.
+ if (!isCStyleType(varType, isVisit))
+ return cacheResult(false);
+ }
+ }
+
+ // 5. All its members are legacy C-Style structs or arrays of legacy C-style structs
+ if (auto arrayType = as<ArrayExpressionType>(type))
+ {
+ if (arrayType->isUnsized())
+ {
+ return cacheResult(false);
+ }
+
+ auto elementType = arrayType->getElementType();
+ if (isDeclRefTypeOf<StructDecl>(elementType))
+ {
+ // Avoid infinite loop in case of circular reference.
+ if (isVisit.contains(elementType))
+ cacheResult(true);
+ }
+
+ if (!isCStyleType(elementType, isVisit))
+ return cacheResult(false);
+ }
+ return cacheResult(true);
+}
+
+Expr* SemanticsVisitor::_createCtorInvokeExpr(
+ Type* toType,
+ const SourceLoc& loc,
+ const List<Expr*>& coercedArgs)
+{
+ auto* varExpr = getASTBuilder()->create<VarExpr>();
+ varExpr->type = (QualType)getASTBuilder()->getTypeType(toType);
+ varExpr->declRef = isDeclRefTypeOf<Decl>(toType);
+
+ auto* constructorExpr = getASTBuilder()->create<ExplicitCtorInvokeExpr>();
+ constructorExpr->functionExpr = varExpr;
+ constructorExpr->arguments.addRange(coercedArgs);
+ constructorExpr->loc = loc;
+
+ return constructorExpr;
+}
+
+// translation from initializer list to constructor invocation if the struct has constructor.
+bool SemanticsVisitor::createInvokeExprForExplicitCtor(
+ Type* toType,
+ InitializerListExpr* fromInitializerListExpr,
+ Expr** outExpr)
+{
+ if (auto toStructDeclRef = isDeclRefTypeOf<StructDecl>(toType))
+ {
+ // TODO: This is just a special case for a backwards-compatibility feature
+ // for HLSL, this flag will imply that the initializer list is synthesized
+ // for a type cast from a literal zero to a 'struct'. In this case, we will fall
+ // back to legacy initializer list logic.
+ if (!fromInitializerListExpr->useCStyleInitialization)
+ {
+ HashSet<Type*> isVisit;
+ if (!isCStyleType(toType, isVisit))
+ return false;
+ }
+
+ if (_hasExplicitConstructor(toStructDeclRef.getDecl(), false))
+ {
+ auto ctorInvokeExpr = _createCtorInvokeExpr(
+ toType,
+ fromInitializerListExpr->loc,
+ fromInitializerListExpr->args);
+
+ DiagnosticSink tempSink(getSourceManager(), nullptr);
+ SemanticsVisitor subVisitor(withSink(&tempSink));
+ ctorInvokeExpr = subVisitor.CheckTerm(ctorInvokeExpr);
+
+ if (tempSink.getErrorCount())
+ {
+ HashSet<Type*> isVisit;
+ if (!isCStyleType(toType, isVisit))
+ {
+ Slang::ComPtr<ISlangBlob> blob;
+ tempSink.getBlobIfNeeded(blob.writeRef());
+ getSink()->diagnoseRaw(
+ Severity::Error,
+ static_cast<char const*>(blob->getBufferPointer()));
+ }
+ return false;
+ }
+
+ if (outExpr)
+ {
+ *outExpr = ctorInvokeExpr;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool SemanticsVisitor::createInvokeExprForSynthesizedCtor(
+ Type* toType,
+ InitializerListExpr* fromInitializerListExpr,
+ Expr** outExpr)
+{
+ StructDecl* structDecl = isDeclRefTypeOf<StructDecl>(toType).getDecl();
+
+ if (!structDecl || !_getSynthesizedConstructor(
+ structDecl,
+ ConstructorDecl::ConstructorFlavor::SynthesizedDefault))
+ return false;
+
+ HashSet<Type*> isVisit;
+ bool isCStyle = isCStyleType(toType, isVisit);
+
+ // TODO: This is just a special case for a backwards-compatibility feature
+ // for HLSL, this flag will imply that the initializer list is synthesized
+ // for a type cast from a literal zero to a 'struct'. In this case, we will fall
+ // back to legacy initializer list logic.
+ if (!fromInitializerListExpr->useCStyleInitialization)
+ {
+ if (isCStyle)
+ return false;
+ }
+
+ DiagnosticSink tempSink(getSourceManager(), nullptr);
+ SemanticsVisitor subVisitor(withSink(&tempSink));
+
+ // First make sure the struct is fully checked, otherwise the synthesized constructor may not be
+ // created yet.
+ subVisitor.ensureDecl(structDecl, DeclCheckState::DefinitionChecked);
+
+ List<Expr*> coercedArgs;
+ auto ctorInvokeExpr =
+ _createCtorInvokeExpr(toType, fromInitializerListExpr->loc, fromInitializerListExpr->args);
+
+ ctorInvokeExpr = subVisitor.CheckExpr(ctorInvokeExpr);
+
+ if (ctorInvokeExpr)
+ {
+ if (!tempSink.getErrorCount())
+ {
+ if (outExpr)
+ *outExpr = ctorInvokeExpr;
+
+ return true;
+ }
+ else if (!isCStyle)
+ {
+ Slang::ComPtr<ISlangBlob> blob;
+ tempSink.getBlobIfNeeded(blob.writeRef());
+ getSink()->diagnoseRaw(
+ Severity::Error,
+ static_cast<char const*>(blob->getBufferPointer()));
+ return false;
+ }
+ }
+ return false;
+}
+
bool SemanticsVisitor::_readAggregateValueFromInitializerList(
Type* inToType,
Expr** outToExpr,
@@ -603,6 +831,21 @@ bool SemanticsVisitor::_coerceInitializerList(
!canCoerce(toType, fromInitializerListExpr->type, nullptr))
return _failedCoercion(toType, outToExpr, fromInitializerListExpr);
+ // Try to invoke the user-defined constructor if it exists. This call will
+ // report error diagnostics if the used-defined constructor exists but does not
+ // match the initialize list.
+ if (createInvokeExprForExplicitCtor(toType, fromInitializerListExpr, outToExpr))
+ {
+ return true;
+ }
+
+ // Try to invoke the synthesized constructor if it exists
+ if (createInvokeExprForSynthesizedCtor(toType, fromInitializerListExpr, outToExpr))
+ {
+ return true;
+ }
+
+ // We will fall back to the legacy logic of initialize list.
if (!_readAggregateValueFromInitializerList(
toType,
outToExpr,
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 7d083e53b..b03126512 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -28,6 +28,7 @@ static List<ConstructorDecl*> _getCtorList(
SemanticsVisitor* visitor,
StructDecl* structDecl,
ConstructorDecl** defaultCtorOut);
+static Expr* constructDefaultInitExprForType(SemanticsVisitor* visitor, VarDeclBase* varDecl);
/// Visitor to transition declarations to `DeclCheckState::CheckedModifiers`
struct SemanticsDeclModifiersVisitor : public SemanticsDeclVisitorBase,
@@ -94,6 +95,18 @@ struct SemanticsDeclAttributesVisitor : public SemanticsDeclVisitorBase,
void checkVarDeclCommon(VarDeclBase* varDecl);
void visitVarDecl(VarDecl* varDecl) { checkVarDeclCommon(varDecl); }
+
+ // Synthesize the constructor declaration for a struct during header visit, as we
+ // need to have such declaration first such that the overloading resolution can lookup
+ // such constructor and complete the initialize list to constructor translation.
+ //
+ // We will defer the actual implementation of the constructor to the body visit, because
+ // we will have full information about each field in the struct during that stage.
+ bool _synthesizeCtorSignature(StructDecl* structDecl);
+ bool collectInitializableMembers(
+ StructDecl* structDecl,
+ const DeclVisibility ctorVisibility,
+ List<VarDeclBase*>& resultMembers);
};
struct SemanticsDeclHeaderVisitor : public SemanticsDeclVisitorBase,
@@ -319,6 +332,7 @@ struct SemanticsDeclBodyVisitor : public SemanticsDeclVisitorBase,
SemanticsContext registerDifferentiableTypesForFunc(FunctionDeclBase* funcDecl);
+private:
struct DeclAndCtorInfo
{
StructDecl* parent = nullptr;
@@ -350,13 +364,21 @@ struct SemanticsDeclBodyVisitor : public SemanticsDeclVisitorBase,
ConstructorDecl* ctor,
List<DeclAndCtorInfo>& inheritanceDefaultCtorList,
ThisExpr* thisExpr,
- SeqStmt* seqStmtChild);
+ SeqStmt* seqStmtChild,
+ bool isMemberInitCtor,
+ Index& paramIndex);
+
void synthesizeCtorBodyForMember(
ConstructorDecl* ctor,
Decl* member,
ThisExpr* thisExpr,
Dictionary<Decl*, Expr*>& cachedDeclToCheckedVar,
- SeqStmt* seqStmtChild);
+ SeqStmt* seqStmtChild,
+ bool isMemberInitCtor,
+ Index& paramIndex);
+
+ MemberExpr* createMemberExpr(ThisExpr* thisExpr, Scope* scope, Decl* member);
+ Expr* createCtorParamExpr(ConstructorDecl* ctor, Index paramIndex);
};
template<typename VisitorType>
@@ -2025,45 +2047,80 @@ void SemanticsDeclHeaderVisitor::checkVarDeclCommon(VarDeclBase* varDecl)
checkVisibility(varDecl);
}
-static ConstructorDecl* _createCtor(
+static void addAutoDiffModifiersToFunc(
SemanticsDeclVisitorBase* visitor,
ASTBuilder* m_astBuilder,
- AggTypeDecl* decl)
+ FunctionDeclBase* func)
+{
+ if (visitor->isTypeDifferentiable(func->returnType.type))
+ {
+ addModifier(func, m_astBuilder->create<BackwardDifferentiableAttribute>());
+ addModifier(func, m_astBuilder->create<ForwardDifferentiableAttribute>());
+ }
+ else
+ addModifier(func, m_astBuilder->create<TreatAsDifferentiableAttribute>());
+}
+
+ConstructorDecl* SemanticsDeclVisitorBase::createCtor(
+ AggTypeDecl* decl,
+ DeclVisibility ctorVisibility)
{
auto ctor = m_astBuilder->create<ConstructorDecl>();
addModifier(ctor, m_astBuilder->create<SynthesizedModifier>());
- auto ctorName = visitor->getName("$init");
+ auto ctorName = getName("$init");
ctor->ownedScope = m_astBuilder->create<Scope>();
ctor->ownedScope->containerDecl = ctor;
- ctor->ownedScope->parent = visitor->getScope(decl);
+ ctor->ownedScope->parent = getScope(decl);
ctor->parentDecl = decl;
ctor->loc = decl->loc;
ctor->closingSourceLoc = ctor->loc;
ctor->nameAndLoc.name = ctorName;
ctor->nameAndLoc.loc = ctor->loc;
- ctor->returnType.type = visitor->calcThisType(makeDeclRef(decl));
+ ctor->returnType.type = calcThisType(makeDeclRef(decl));
auto body = m_astBuilder->create<BlockStmt>();
body->scopeDecl = m_astBuilder->create<ScopeDecl>();
body->scopeDecl->ownedScope = m_astBuilder->create<Scope>();
- body->scopeDecl->ownedScope->parent = visitor->getScope(ctor);
+ body->scopeDecl->ownedScope->parent = getScope(ctor);
body->scopeDecl->parentDecl = ctor;
body->scopeDecl->loc = ctor->loc;
body->scopeDecl->closingSourceLoc = ctor->loc;
body->closingSourceLoc = ctor->closingSourceLoc;
ctor->body = body;
body->body = m_astBuilder->create<SeqStmt>();
- ctor->isSynthesized = true;
+ ctor->addFlavor(ConstructorDecl::ConstructorFlavor::SynthesizedDefault);
decl->addMember(ctor);
+ addAutoDiffModifiersToFunc(this, m_astBuilder, ctor);
+ addVisibilityModifier(ctor, ctorVisibility);
return ctor;
}
+static inline bool _isDefaultCtor(ConstructorDecl* ctor)
+{
+ auto allParamHaveInitExpr = [](ConstructorDecl* ctor)
+ {
+ for (auto i : ctor->getParameters())
+ if (!i->initExpr)
+ return false;
+ return true;
+ };
+
+ // 1. default ctor must have no parameters
+ // 2. default ctor can have parameters, but all parameters have init expr (Because we won't
+ // differentiate this case from 2.)
+ if (ctor->members.getCount() == 0 || allParamHaveInitExpr(ctor))
+ {
+ return true;
+ }
+
+ return false;
+}
+
static ConstructorDecl* _getDefaultCtor(StructDecl* structDecl)
{
for (auto ctor : structDecl->getMembersOfType<ConstructorDecl>())
{
- if (!ctor->body || ctor->members.getCount() != 0)
- continue;
- return ctor;
+ if (_isDefaultCtor(ctor))
+ return ctor;
}
return nullptr;
}
@@ -2095,9 +2152,8 @@ static List<ConstructorDecl*> _getCtorList(
if (!ctor || !ctor->body)
return;
ctorList.add(ctor);
- if (ctor->members.getCount() != 0)
- return;
- *defaultCtorOut = ctor;
+ if (_isDefaultCtor(ctor))
+ *defaultCtorOut = ctor;
};
if (ctorLookupResult.items.getCount() == 0)
{
@@ -2208,16 +2264,10 @@ bool isDefaultInitializable(VarDeclBase* varDecl)
return true;
}
-static Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, VarDeclBase* varDecl)
+static Expr* constructDefaultConstructorForType(SemanticsVisitor* visitor, Type* type)
{
- if (!varDecl->type || !varDecl->type.type)
- return nullptr;
-
- if (!isDefaultInitializable(varDecl))
- return nullptr;
-
ConstructorDecl* defaultCtor = nullptr;
- auto declRefType = as<DeclRefType>(varDecl->type.type);
+ auto declRefType = as<DeclRefType>(type);
if (declRefType)
{
if (auto structDecl = as<StructDecl>(declRefType->getDeclRef().getDecl()))
@@ -2225,7 +2275,6 @@ static Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, VarDeclBa
defaultCtor = _getDefaultCtor(structDecl);
}
}
-
if (defaultCtor)
{
auto* invoke = visitor->getASTBuilder()->create<InvokeExpr>();
@@ -2239,6 +2288,22 @@ static Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, VarDeclBa
nullptr);
return invoke;
}
+
+ return nullptr;
+}
+
+static Expr* constructDefaultInitExprForType(SemanticsVisitor* visitor, VarDeclBase* varDecl)
+{
+ if (!varDecl->type || !varDecl->type.type)
+ return nullptr;
+
+ if (!isDefaultInitializable(varDecl))
+ return nullptr;
+
+ if (auto defaultInitExpr = constructDefaultConstructorForType(visitor, varDecl->type.type))
+ {
+ return defaultInitExpr;
+ }
else
{
auto* defaultCall = visitor->getASTBuilder()->create<DefaultConstructExpr>();
@@ -2255,7 +2320,7 @@ void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl)
if (getOptionSet().hasOption(CompilerOptionName::ZeroInitialize) && !varDecl->initExpr &&
as<VarDecl>(varDecl))
{
- varDecl->initExpr = constructDefaultInitExprForVar(this, varDecl);
+ varDecl->initExpr = constructDefaultInitExprForType(this, varDecl);
}
if (auto initExpr = varDecl->initExpr)
@@ -2274,6 +2339,7 @@ void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl)
if (initExpr->type.isWriteOnly)
getSink()->diagnose(initExpr, Diagnostics::readingFromWriteOnly);
+
initExpr = coerce(CoercionSite::Initializer, varDecl->type.Ptr(), initExpr);
varDecl->initExpr = initExpr;
@@ -2361,11 +2427,21 @@ void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl)
// for the variable, that will be used for all downstream
// code generation.
//
- varDecl->initExpr =
- CompleteOverloadCandidate(overloadContext, *overloadContext.bestCandidate);
- getShared()->cacheImplicitCastMethod(
- key,
- ImplicitCastMethod{*overloadContext.bestCandidate, 0});
+ auto constructorDecl =
+ as<ConstructorDecl>(overloadContext.bestCandidate->item.declRef).getDecl();
+ // We don't allow implicit initialization of struct only have synthesized default
+ // ctor.
+ if ((constructorDecl &&
+ !constructorDecl->containsFlavor(
+ ConstructorDecl::ConstructorFlavor::SynthesizedDefault)) ||
+ !constructorDecl)
+ {
+ varDecl->initExpr =
+ CompleteOverloadCandidate(overloadContext, *overloadContext.bestCandidate);
+ getShared()->cacheImplicitCastMethod(
+ key,
+ ImplicitCastMethod{*overloadContext.bestCandidate, 0});
+ }
}
}
}
@@ -2478,18 +2554,18 @@ void SemanticsVisitor::CheckConstraintSubType(TypeExp& typeExp)
}
}
-void addVisibilityModifier(ASTBuilder* builder, Decl* decl, DeclVisibility vis)
+void SemanticsVisitor::addVisibilityModifier(Decl* decl, DeclVisibility vis)
{
switch (vis)
{
case DeclVisibility::Public:
- addModifier(decl, builder->create<PublicModifier>());
+ addModifier(decl, m_astBuilder->create<PublicModifier>());
break;
case DeclVisibility::Internal:
- addModifier(decl, builder->create<InternalModifier>());
+ addModifier(decl, m_astBuilder->create<InternalModifier>());
break;
case DeclVisibility::Private:
- addModifier(decl, builder->create<PrivateModifier>());
+ addModifier(decl, m_astBuilder->create<PrivateModifier>());
break;
default:
break;
@@ -2635,7 +2711,7 @@ bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness
aggTypeDecl->members.add(diffField);
auto visibility = getDeclVisibility(member);
- addVisibilityModifier(m_astBuilder, diffField, visibility);
+ addVisibilityModifier(diffField, visibility);
aggTypeDecl->invalidateMemberDictionary();
@@ -2748,7 +2824,7 @@ bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness
auto requirementVisibility = getDeclVisibility(requirementDeclRef.getDecl());
auto thisVisibility = getDeclVisibility(context->parentDecl);
auto visibility = Math::Min(thisVisibility, requirementVisibility);
- addVisibilityModifier(m_astBuilder, aggTypeDecl, visibility);
+ addVisibilityModifier(aggTypeDecl, visibility);
}
// Synthesize the rest of IDifferential method conformances by recursively checking
@@ -4411,7 +4487,7 @@ void SemanticsVisitor::addModifiersToSynthesizedDecl(
auto requirementVisibility = getDeclVisibility(requiredMemberDeclRef.getDecl());
auto thisVisibility = getDeclVisibility(context->parentDecl);
auto visibility = Math::Min(thisVisibility, requirementVisibility);
- addVisibilityModifier(m_astBuilder, synthesized, visibility);
+ addVisibilityModifier(synthesized, visibility);
}
}
@@ -5318,7 +5394,7 @@ bool SemanticsVisitor::trySynthesizePropertyRequirementWitness(
auto requirementVisibility = getDeclVisibility(requiredMemberDeclRef.getDecl());
auto thisVisibility = getDeclVisibility(context->parentDecl);
auto visibility = Math::Min(thisVisibility, requirementVisibility);
- addVisibilityModifier(m_astBuilder, synPropertyDecl, visibility);
+ addVisibilityModifier(synPropertyDecl, visibility);
}
return true;
}
@@ -5487,7 +5563,7 @@ bool SemanticsVisitor::trySynthesizeWrapperTypePropertyRequirementWitness(
if (innerProperty.getDecl()->findModifier<VisibilityModifier>())
{
auto vis = getDeclVisibility(innerProperty.getDecl());
- addVisibilityModifier(m_astBuilder, synPropertyDecl, vis);
+ addVisibilityModifier(synPropertyDecl, vis);
}
context->parentDecl->addMember(synPropertyDecl);
@@ -5874,7 +5950,7 @@ bool SemanticsVisitor::trySynthesizeWrapperTypeSubscriptRequirementWitness(
auto requirementVisibility = getDeclVisibility(requiredMemberDeclRef.getDecl());
auto thisVisibility = getDeclVisibility(context->parentDecl);
auto visibility = Math::Min(thisVisibility, requirementVisibility);
- addVisibilityModifier(m_astBuilder, synSubscriptDecl, visibility);
+ addVisibilityModifier(synSubscriptDecl, visibility);
}
return true;
@@ -5995,7 +6071,7 @@ bool SemanticsVisitor::trySynthesizeSubscriptRequirementWitness(
auto requirementVisibility = getDeclVisibility(requiredMemberDeclRef.getDecl());
auto thisVisibility = getDeclVisibility(context->parentDecl);
auto visibility = Math::Min(thisVisibility, requirementVisibility);
- addVisibilityModifier(m_astBuilder, synSubscriptDecl, visibility);
+ addVisibilityModifier(synSubscriptDecl, visibility);
}
return true;
@@ -7670,6 +7746,43 @@ void SemanticsVisitor::validateEnumTagType(Type* type, SourceLoc const& loc)
getSink()->diagnose(loc, Diagnostics::invalidEnumTagType, type);
}
+bool SemanticsVisitor::_hasExplicitConstructor(StructDecl* structDecl, bool checkBaseType)
+{
+ if (!structDecl)
+ return false;
+
+ auto _hasExplicitCtor = [](AggTypeDecl* aggDecl) -> bool
+ {
+ // First check if the extension of this struct defines an explicit constructor.
+ for (auto ctor : aggDecl->getMembersOfType<ConstructorDecl>())
+ {
+ // constructor that is not synthesized must be user defined.
+ if (ctor->findModifier<SynthesizedModifier>() == nullptr)
+ {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ if (_hasExplicitCtor(structDecl))
+ return true;
+
+ if (!checkBaseType)
+ return false;
+
+ for (auto inheritanceMember : structDecl->getMembersOfType<InheritanceDecl>())
+ {
+ auto baseTypeDecl = isDeclRefTypeOf<AggTypeDecl>(inheritanceMember->base.type);
+ if (baseTypeDecl && !as<InterfaceDecl>(baseTypeDecl))
+ {
+ if (_hasExplicitCtor(baseTypeDecl.getDecl()))
+ return true;
+ }
+ }
+ return false;
+}
+
void SemanticsDeclBasesVisitor::visitEnumDecl(EnumDecl* decl)
{
SLANG_OUTER_SCOPE_CONTEXT_DECL_RAII(this, decl);
@@ -9064,31 +9177,97 @@ static SeqStmt* _ensureCtorBodyIsSeqStmt(ASTBuilder* m_astBuilder, ConstructorDe
return as<SeqStmt>(stmt->body);
}
+MemberExpr* SemanticsDeclBodyVisitor::createMemberExpr(
+ ThisExpr* thisExpr,
+ Scope* scope,
+ Decl* member)
+{
+ MemberExpr* memberExpr = m_astBuilder->create<MemberExpr>();
+ memberExpr->baseExpression = thisExpr;
+ memberExpr->declRef = member->getDefaultDeclRef();
+ memberExpr->scope = scope;
+ memberExpr->loc = member->loc;
+ memberExpr->name = member->getName();
+ memberExpr->type = GetTypeForDeclRef(member->getDefaultDeclRef(), member->loc);
+
+ return memberExpr;
+}
+
+Expr* SemanticsDeclBodyVisitor::createCtorParamExpr(ConstructorDecl* ctor, Index paramIndex)
+{
+ if (paramIndex < ctor->members.getCount())
+ {
+ if (auto param = as<ParamDecl>(ctor->members[paramIndex]))
+ {
+ auto paramType = param->getType();
+ auto paramExpr = m_astBuilder->create<VarExpr>();
+ paramExpr->scope = ctor->ownedScope;
+ paramExpr->declRef = param;
+ paramExpr->type = paramType;
+ paramExpr->loc = param->loc;
+ return paramExpr;
+ }
+ }
+ return nullptr;
+}
+
void SemanticsDeclBodyVisitor::synthesizeCtorBodyForBases(
ConstructorDecl* ctor,
List<DeclAndCtorInfo>& inheritanceDefaultCtorList,
ThisExpr* thisExpr,
- SeqStmt* seqStmtChild)
+ SeqStmt* seqStmtChild,
+ bool isMemberInitCtor,
+ Index& ioParamIndex)
{
- // e.g. this->base = BaseType();
for (auto& declInfo : inheritanceDefaultCtorList)
{
- if (!declInfo.defaultCtor)
- continue;
+ ConstructorDecl* baseCtor = nullptr;
+ List<Expr*> argumentList;
+
+ if (isMemberInitCtor)
+ {
+ // Pick the parameters from the member initialize ctor, and use them to invoke the
+ // base's member initialize ctor. e.g. base->init(...);
+ baseCtor = _getSynthesizedConstructor(
+ declInfo.parent,
+ ConstructorDecl::ConstructorFlavor::SynthesizedMemberInit);
+ if (baseCtor)
+ {
+ Index idx = 0;
+ for (; idx < baseCtor->getParameters().getCount(); idx++)
+ {
+ auto paramExpr = createCtorParamExpr(ctor, idx);
+ argumentList.add(paramExpr);
+ }
+ ioParamIndex += idx;
+ }
+ }
+
+ // It's possible that the base type doesn't have a member initialize ctor, in this case, we
+ // should use the default ctor.
+ if (!baseCtor)
+ {
+ // If the base type has no default constructor, it means that it's not default
+ // initializable, e.g. unsized array, resource type, etc. We will not synthesize code to
+ // initialize it.
+ if (!declInfo.defaultCtor)
+ continue;
+ baseCtor = declInfo.defaultCtor;
+ }
auto declRefType = as<DeclRefType>(declInfo.type);
auto ctorToInvoke = m_astBuilder->create<VarExpr>();
ctorToInvoke->declRef = declRefType->getDeclRef();
- ctorToInvoke->name = declInfo.defaultCtor->getName();
- ctorToInvoke->loc = declInfo.defaultCtor->loc;
+ ctorToInvoke->name = baseCtor->getName();
+ ctorToInvoke->loc = baseCtor->loc;
ctorToInvoke->type = m_astBuilder->getFuncType(ArrayView<Type*>(), declRefType);
auto invoke = m_astBuilder->create<InvokeExpr>();
invoke->functionExpr = ctorToInvoke;
+ invoke->arguments.addRange(argumentList);
auto assign = m_astBuilder->create<AssignExpr>();
-
assign->left = coerce(CoercionSite::Initializer, declRefType, thisExpr);
assign->right = invoke;
@@ -9105,25 +9284,57 @@ void SemanticsDeclBodyVisitor::synthesizeCtorBodyForMember(
Decl* member,
ThisExpr* thisExpr,
Dictionary<Decl*, Expr*>& cachedDeclToCheckedVar,
- SeqStmt* seqStmtChild)
+ SeqStmt* seqStmtChild,
+ bool isMemberInitCtor,
+ Index& paramIndex)
{
auto varDeclBase = as<VarDeclBase>(member);
// Static variables are initialized at start of runtime, not inside a constructor
- if (!varDeclBase || !varDeclBase->initExpr || varDeclBase->hasModifier<HLSLStaticModifier>())
+ // Once thing to notice is that if a member variable doesn't have name, it must be synthesized
+ // instead of defined by user, we should not put it into the constructor because it's not a real
+ // member.
+ if (!varDeclBase || varDeclBase->hasModifier<HLSLStaticModifier>() ||
+ varDeclBase->getName() == nullptr)
return;
- MemberExpr* memberExpr = m_astBuilder->create<MemberExpr>();
- memberExpr->baseExpression = thisExpr;
- memberExpr->declRef = member->getDefaultDeclRef();
- memberExpr->scope = ctor->ownedScope;
- memberExpr->loc = member->loc;
- memberExpr->name = member->getName();
- memberExpr->type = DeclRefType::create(getASTBuilder(), member->getDefaultDeclRef());
+ Expr* initExpr = nullptr;
+ auto structDecl = as<StructDecl>(member->parentDecl);
+ bool useParamList = isMemberInitCtor;
+ useParamList = isMemberInitCtor && structDecl->m_membersVisibleInCtor.contains(varDeclBase);
+
+ if (!useParamList)
+ {
+ // If this is not a synthesized constructor (e.g. explicit ctor), or
+ // the member has no visibility, we can only use it's init expression to initialize it.
+ if (!varDeclBase->initExpr)
+ return;
+ initExpr = varDeclBase->initExpr;
+ }
+ else
+ {
+ // Find the corresponding parameter, if we can't find it, there
+ // must be something wrong, it indicates that the ctor signature
+ // is incorrect that the parameter list doesn't match the member list.
+ initExpr = createCtorParamExpr(ctor, paramIndex++);
+ if (!initExpr)
+ {
+ const char* structName =
+ (structDecl->getName() ? structDecl->getName()->text.begin() : "unknown");
+ StringBuilder msg;
+ msg << "Fail to synthesize the member initialize constructor for struct '" << structName
+ << "', the parameter list doesn't match the member list.";
+ SLANG_ABORT_COMPILATION(msg.produceString().begin());
+ }
+ }
+
+ MemberExpr* memberExpr = createMemberExpr(thisExpr, ctor->ownedScope, member);
+ if (!memberExpr->type.isLeftValue)
+ return;
auto assign = m_astBuilder->create<AssignExpr>();
assign->left = memberExpr;
- assign->right = varDeclBase->initExpr;
+ assign->right = initExpr;
assign->loc = member->loc;
auto stmt = m_astBuilder->create<ExpressionStmt>();
@@ -9139,9 +9350,6 @@ void SemanticsDeclBodyVisitor::synthesizeCtorBodyForMember(
cachedDeclToCheckedVar.add({member, checkedMemberVarExpr});
}
- if (!checkedMemberVarExpr->type.isLeftValue)
- return;
-
seqStmtChild->stmts.add(stmt);
}
@@ -9163,14 +9371,37 @@ void SemanticsDeclBodyVisitor::synthesizeCtorBody(
thisExpr->scope = ctor->ownedScope;
thisExpr->type = ctor->returnType.type;
- // Initialize base type by using its default constructor if it has one.
- synthesizeCtorBodyForBases(ctor, inheritanceDefaultCtorList, thisExpr, seqStmtChild);
-
- // Initialize member variables by using their default value if they have one
- // e.g. this->member = default_value
+ // We treat the ctor with parameters and all parameters have default value as default ctor
+ // as well, but the method to synthesize them are totally different, therefore, we need to
+ // differentiate them here.
+ bool isMemberInitCtor =
+ ctor->containsFlavor(ConstructorDecl::ConstructorFlavor::SynthesizedMemberInit);
+
+ // When we synthesize the member initialize constructor, we need to use the parameters in
+ // the function body, so this inout parameter is used to keep track of the index of the
+ // parameters.
+ Index ioParamIndex = 0;
+
+ // The first step is to synthesize the initialization of the base member.
+ synthesizeCtorBodyForBases(
+ ctor,
+ inheritanceDefaultCtorList,
+ thisExpr,
+ seqStmtChild,
+ isMemberInitCtor,
+ ioParamIndex);
+
+ // Then synthesize the initialization of the other members.
for (auto& m : structDecl->members)
{
- synthesizeCtorBodyForMember(ctor, m, thisExpr, cachedDeclToCheckedVar, seqStmtChild);
+ synthesizeCtorBodyForMember(
+ ctor,
+ m,
+ thisExpr,
+ cachedDeclToCheckedVar,
+ seqStmtChild,
+ isMemberInitCtor,
+ ioParamIndex);
}
if (seqStmtChild->stmts.getCount() != 0)
@@ -9224,7 +9455,7 @@ void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl)
ensureDecl(m->getDefaultDeclRef(), DeclCheckState::DefaultConstructorReadyForUse);
if (!isDefaultInitializableType || varDeclBase->initExpr)
continue;
- varDeclBase->initExpr = constructDefaultInitExprForVar(this, varDeclBase);
+ varDeclBase->initExpr = constructDefaultInitExprForType(this, varDeclBase);
}
synthesizeCtorBody(structDeclInfo, inheritanceDefaultCtorList, structDecl);
@@ -9776,7 +10007,7 @@ Type* SemanticsVisitor::findResultTypeForConstructorDecl(ConstructorDecl* decl)
void SemanticsDeclHeaderVisitor::visitConstructorDecl(ConstructorDecl* decl)
{
- // We need to compute the result tyep for this declaration,
+ // We need to compute the result type for this declaration,
// since it wasn't filled in for us.
decl->returnType.type = findResultTypeForConstructorDecl(decl);
@@ -11976,13 +12207,174 @@ void SemanticsDeclAttributesVisitor::checkPrimalSubstituteOfAttribute(
DeclAssociationKind::PrimalSubstituteFunc);
}
+bool SemanticsDeclAttributesVisitor::collectInitializableMembers(
+ StructDecl* structDecl,
+ const DeclVisibility ctorVisibility,
+ List<VarDeclBase*>& resultMembers)
+{
+ auto findMembers = [&](StructDecl* structDecl)
+ {
+ for (auto varDeclRef : getMembersOfType<VarDeclBase>(
+ getASTBuilder(),
+ structDecl,
+ MemberFilterStyle::Instance))
+ {
+ auto varDecl = varDeclRef.getDecl();
+ if (getDeclVisibility(varDecl) < ctorVisibility)
+ continue;
+
+ auto type = GetTypeForDeclRef(varDeclRef, varDecl->loc);
+ if (!type.isLeftValue)
+ continue;
+
+ resultMembers.add(varDecl);
+ structDecl->m_membersVisibleInCtor.add(varDecl);
+ }
+ };
+
+ // Find the base type's members first
+ for (auto inheritanceMember : structDecl->getMembersOfType<InheritanceDecl>())
+ {
+ // For base types, we need to pick their parameters of the constructor to the derived type's
+ // constructor
+ if (auto baseTypeDeclRef = isDeclRefTypeOf<StructDecl>(inheritanceMember->base.type))
+ {
+ // We should only find the member initialization constructor because it is the
+ // constructor has parameters
+ ConstructorDecl* ctor = _getSynthesizedConstructor(
+ baseTypeDeclRef.getDecl(),
+ ConstructorDecl::ConstructorFlavor::SynthesizedMemberInit);
+
+ // The constructor has to have higher or equal visibility level than the struct itself,
+ // otherwise, it's not accessible so we will not pick up.
+ if (ctor && getDeclVisibility(ctor) >= ctorVisibility)
+ {
+ for (ParamDecl* param : ctor->getParameters())
+ {
+ // Because the parameters in the ctor must have the higher or equal visibility
+ // than the ctor itself, we don't need to check the visibility level of the
+ // parameter.
+ resultMembers.add(param);
+ }
+ }
+ }
+ }
+
+ // Find the struct's members
+ findMembers(structDecl);
+ return (resultMembers.getCount() > 0);
+}
+
+// If a struct's member:
+// 1. has an initialize expression: Struct S {int a = 1;}; or
+// 2. is a default initializable type
+// Note, If a type is not default initializable, it doesn't have default value.
+// it can be associated with default value expression in the constructor signature.
+// This function helps to check whether either of those 2 conditions are met and create
+// a default value for the parameter.
+// It's totally fine that there is no default value for the parameter, in this case, user
+// code has to provide the argument for this parameter.
+static Expr* _getParamDefaultValue(SemanticsVisitor* visitor, VarDeclBase* varDecl)
+{
+ // 1st condition is easy, we can just use the init expression as the default value.
+ if (varDecl->initExpr)
+ {
+ return varDecl->initExpr;
+ }
+
+ if (!varDecl->type || !varDecl->type.type)
+ return nullptr;
+
+ if (!isDefaultInitializable(varDecl))
+ return nullptr;
+
+ return constructDefaultConstructorForType(visitor, varDecl->type.type);
+}
+
+bool SemanticsDeclAttributesVisitor::_synthesizeCtorSignature(StructDecl* structDecl)
+{
+ // If a type or its base type already defines any explicit constructors, do not synthesize any
+ // constructors. see:
+ // https://github.com/shader-slang/slang/blob/master/docs/proposals/004-initialization.md#inheritance-initialization
+ if (_hasExplicitConstructor(structDecl, true))
+ return false;
+
+ // synthesize the signature first.
+ // The constructor's visibility level is the same as the struct itself.
+ // See:
+ // https://github.com/shader-slang/slang/blob/master/docs/proposals/004-initialization.md#synthesis-of-constructors-for-member-initialization
+ DeclVisibility ctorVisibility = getDeclVisibility(structDecl);
+
+ // Only the members whose visibility level is higher or equal than the
+ // constructor's visibility level will appear in the constructor's parameter list.
+ List<VarDeclBase*> resultMembers;
+ if (!collectInitializableMembers(structDecl, ctorVisibility, resultMembers))
+ return false;
+
+ // synthesize the constructor signature:
+ // 1. The constructor's name is always `$init`, we create one without parameters now.
+ ConstructorDecl* ctor = createCtor(structDecl, ctorVisibility);
+ ctor->addFlavor(ConstructorDecl::ConstructorFlavor::SynthesizedMemberInit);
+
+ ctor->members.reserve(resultMembers.getCount());
+
+ // 2. Add the parameter list
+ bool stopProcessingDefaultValues = false;
+ for (SlangInt i = resultMembers.getCount() - 1; i >= 0; i--)
+ {
+ auto member = resultMembers[i];
+ auto parentAggDecl = getParentAggTypeDecl(member);
+ ;
+
+ auto ctorParam = m_astBuilder->create<ParamDecl>();
+ ctorParam->type = (TypeExp)member->type;
+
+ if (!stopProcessingDefaultValues)
+ ctorParam->initExpr = _getParamDefaultValue(this, member);
+
+ if (!ctorParam->initExpr)
+ stopProcessingDefaultValues = true;
+
+ ctorParam->parentDecl = ctor;
+
+ Name* paramName =
+ (parentAggDecl == structDecl)
+ ? member->getName()
+ : getName(parentAggDecl->getName()->text + "_" + member->getName()->text);
+
+ ctorParam->nameAndLoc = NameLoc(paramName, ctor->loc);
+
+ ctorParam->loc = ctor->loc;
+ ctor->members.add(ctorParam);
+
+ // We need to ensure member is `no_diff` if it cannot be differentiated, `ctor` modifiers do
+ // not matter in this case since member-wise ctor is always differentiable or "treat as
+ // differentiable".
+ if (!isTypeDifferentiable(member->getType()) || member->hasModifier<NoDiffModifier>())
+ {
+ auto noDiffMod = m_astBuilder->create<NoDiffModifier>();
+ noDiffMod->loc = ctorParam->loc;
+ addModifier(ctorParam, noDiffMod);
+ }
+ }
+ ctor->members.reverse();
+ return true;
+}
+
void SemanticsDeclAttributesVisitor::visitStructDecl(StructDecl* structDecl)
{
- // add a empty deault CTor if missing; checking in attributes
- // to avoid circular checking logic
- auto defaultCtor = _getDefaultCtor(structDecl);
- if (!defaultCtor)
- _createCtor(this, m_astBuilder, structDecl);
+ // add the member initialize constructor here to avoid circular checking logic
+ if (!_synthesizeCtorSignature(structDecl))
+ {
+ // add a default CTor if missing; checking in attributes
+ // to avoid circular checking logic
+ auto defaultCtor = _getDefaultCtor(structDecl);
+ if (!defaultCtor)
+ {
+ DeclVisibility ctorVisibility = getDeclVisibility(structDecl);
+ createCtor(structDecl, ctorVisibility);
+ }
+ }
int backingWidth = 0;
[[maybe_unused]] int totalWidth = 0;
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index 135632ba8..7726fd6c8 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -2909,7 +2909,7 @@ Expr* SemanticsExprVisitor::convertToLogicOperatorExpr(InvokeExpr* expr)
if (auto varExpr = as<VarExpr>(expr->functionExpr))
{
- if ((varExpr->name->text == "&&") || (varExpr->name->text == "||"))
+ if ((getText(varExpr->name) == "&&") || (getText(varExpr->name) == "||"))
{
// We only use short-circuiting in scalar input, will fall back
// to non-short-circuiting in vector input.
@@ -3790,8 +3790,10 @@ Expr* SemanticsExprVisitor::visitTypeCastExpr(TypeCastExpr* expr)
InitializerListExpr* initListExpr =
m_astBuilder->create<InitializerListExpr>();
initListExpr->loc = expr->loc;
+ initListExpr->useCStyleInitialization = false;
auto checkedInitListExpr = visitInitializerListExpr(initListExpr);
+
return coerce(CoercionSite::General, typeExp.type, checkedInitListExpr);
}
}
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index 638706814..3276b7534 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -760,6 +760,12 @@ public:
m_mapTypePairToImplicitCastMethod[key] = candidate;
}
+ bool* isCStyleType(Type* type) { return m_isCStyleTypeCache.tryGetValue(type); }
+
+ void cacheCStyleType(Type* type, bool isCStyle)
+ {
+ m_isCStyleTypeCache.addIfNotExists(type, isCStyle);
+ }
// Get the inner most generic decl that a decl-ref is dependent on.
// For example, `Foo<T>` depends on the generic decl that defines `T`.
//
@@ -889,6 +895,7 @@ private:
Dictionary<DeclRef<Decl>, InheritanceInfo> m_mapDeclRefToInheritanceInfo;
Dictionary<TypePair, SubtypeWitness*> m_mapTypePairToSubtypeWitness;
Dictionary<ImplicitCastMethodKey, ImplicitCastMethod> m_mapTypePairToImplicitCastMethod;
+ Dictionary<Type*, bool> m_isCStyleTypeCache;
};
/// Local/scoped state of the semantic-checking system
@@ -2780,6 +2787,25 @@ public:
void suggestCompletionItems(
CompletionSuggestions::ScopeKind scopeKind,
LookupResult const& lookupResult);
+
+ bool createInvokeExprForExplicitCtor(
+ Type* toType,
+ InitializerListExpr* fromInitializerListExpr,
+ Expr** outExpr);
+
+ bool createInvokeExprForSynthesizedCtor(
+ Type* toType,
+ InitializerListExpr* fromInitializerListExpr,
+ Expr** outExpr);
+
+ Expr* _createCtorInvokeExpr(Type* toType, const SourceLoc& loc, const List<Expr*>& coercedArgs);
+ bool _hasExplicitConstructor(StructDecl* structDecl, bool checkBaseType);
+ ConstructorDecl* _getSynthesizedConstructor(
+ StructDecl* structDecl,
+ ConstructorDecl::ConstructorFlavor flavor);
+ bool isCStyleType(Type* type, HashSet<Type*>& isVisit);
+
+ void addVisibilityModifier(Decl* decl, DeclVisibility vis);
};
@@ -2999,6 +3025,8 @@ struct SemanticsDeclVisitorBase : public SemanticsVisitor
}
void checkModule(ModuleDecl* programNode);
+
+ ConstructorDecl* createCtor(AggTypeDecl* decl, DeclVisibility ctorVisibility);
};
bool isUnsizedArrayType(Type* type);
diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp
index bca2f7587..b944d2bf4 100644
--- a/source/slang/slang-check-overload.cpp
+++ b/source/slang/slang-check-overload.cpp
@@ -1313,6 +1313,21 @@ int SemanticsVisitor::CompareLookupResultItems(
bool rightIsExtension = as<ExtensionDecl>(rightDeclRefParent.getDecl()) != nullptr;
if (leftIsExtension != rightIsExtension)
{
+ // Add a special case for constructors, where we prefer the one that is not synthesized,
+ if (auto leftCtor = as<ConstructorDecl>(left.declRef.getDecl()))
+ {
+ auto rightCtor = as<ConstructorDecl>(right.declRef.getDecl());
+ bool leftIsSynthesized =
+ leftCtor->containsFlavor(ConstructorDecl::ConstructorFlavor::SynthesizedDefault);
+ bool rightIsSynthesized =
+ rightCtor->containsFlavor(ConstructorDecl::ConstructorFlavor::SynthesizedDefault);
+
+ if (leftIsSynthesized != rightIsSynthesized)
+ {
+ return int(leftIsSynthesized) - int(rightIsSynthesized);
+ }
+ }
+
return int(leftIsExtension) - int(rightIsExtension);
}
else if (leftIsExtension)
@@ -2177,7 +2192,6 @@ void SemanticsVisitor::AddTypeOverloadCandidates(Type* type, OverloadResolveCont
context.sourceScope,
LookupMask::Default,
options);
-
AddOverloadCandidates(initializers, context);
}
@@ -2546,7 +2560,6 @@ Expr* SemanticsVisitor::ResolveInvoke(InvokeExpr* expr)
context.loc = expr->loc;
context.sourceScope = m_outerScope;
context.baseExpr = GetBaseExpr(funcExpr);
-
// We run a special case here where an `InvokeExpr`
// with a single argument where the base/func expression names
// a type should always be treated as an explicit type coercion
@@ -2565,7 +2578,7 @@ Expr* SemanticsVisitor::ResolveInvoke(InvokeExpr* expr)
// type coercion.
bool typeOverloadChecked = false;
- if (expr->arguments.getCount() == 1)
+ if (expr->arguments.getCount() == 1 && !as<ExplicitCtorInvokeExpr>(expr))
{
if (const auto typeType = as<TypeType>(funcExpr->type))
{
diff --git a/source/slang/slang-ir-check-differentiability.cpp b/source/slang/slang-ir-check-differentiability.cpp
index d18c47689..9001295e0 100644
--- a/source/slang/slang-ir-check-differentiability.cpp
+++ b/source/slang/slang-ir-check-differentiability.cpp
@@ -249,6 +249,11 @@ public:
if (outerFuncInst->findDecoration<IRTorchEntryPointDecoration>())
return;
+ bool isSynthesizeConstructor = false;
+
+ if (auto constructor = funcInst->findDecoration<IRConstructorDecorartion>())
+ isSynthesizeConstructor = constructor->getSynthesizedStatus();
+
// This is a kernel function, we don't allow using TorchTensor type here.
for (auto b : funcInst->getBlocks())
{
@@ -256,6 +261,13 @@ public:
{
if (!checkType(inst->getDataType()))
{
+ if (isSynthesizeConstructor)
+ {
+ IRBuilder irBuilder(funcInst);
+ irBuilder.addDecoration(funcInst, kIROp_CudaHostDecoration);
+ return;
+ }
+
auto loc = inst->sourceLoc;
if (!loc.isValid())
loc = funcInst->sourceLoc;
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 7f399c366..a966189a0 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -10330,7 +10330,10 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
}
// Used for diagnostics
- getBuilder()->addConstructorDecoration(irFunc, constructorDecl->isSynthesized);
+ getBuilder()->addConstructorDecoration(
+ irFunc,
+ constructorDecl->containsFlavor(
+ ConstructorDecl::ConstructorFlavor::SynthesizedDefault));
}
// We lower whatever statement was stored on the declaration
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index 2b4d64cd9..87c62f7ee 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -384,13 +384,6 @@ void initCommandOptions(CommandOptions& options)
"-restrictive-capability-check",
nullptr,
"Many capability warnings will become an error."},
- {OptionKind::ZeroInitialize,
- "-zero-initialize",
- nullptr,
- "Initialize all variables to zero."
- "Structs will set all struct-fields without an init expression to 0."
- "All variables will call their default constructor if not explicitly initialized as "
- "usual."},
{OptionKind::IgnoreCapabilities,
"-ignore-capabilities",
nullptr,
@@ -914,6 +907,13 @@ void initCommandOptions(CommandOptions& options)
"-parameter-blocks-use-register-spaces",
nullptr,
"Parameter blocks will use register spaces"},
+ {OptionKind::ZeroInitialize,
+ "-zero-initialize",
+ nullptr,
+ "Initialize all variables to zero."
+ "Structs will set all struct-fields without an init expression to 0."
+ "All variables will call their default constructor if not explicitly initialized as "
+ "usual."},
};
_addOptions(makeConstArrayView(deprecatedOpts), options);
@@ -2138,7 +2138,6 @@ SlangResult OptionsParser::_parse(int argc, char const* const* argv)
case OptionKind::VulkanUseEntryPointName:
case OptionKind::VulkanUseGLLayout:
case OptionKind::VulkanEmitReflection:
- case OptionKind::ZeroInitialize:
case OptionKind::IgnoreCapabilities:
case OptionKind::RestrictiveCapabilityCheck:
case OptionKind::MinimumSlangOptimization:
diff --git a/tests/autodiff/differential-type-constructor.slang b/tests/autodiff/differential-type-constructor.slang
index 9afff878d..96cf1272e 100644
--- a/tests/autodiff/differential-type-constructor.slang
+++ b/tests/autodiff/differential-type-constructor.slang
@@ -14,12 +14,12 @@ RWStructuredBuffer<float> outputBuffer;
void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
{
{
- var dp = diffPair(MyStruct(), MyStruct.Differential());
+ var dp = diffPair(MyStruct(0.0, 0), MyStruct.Differential(0.0));
outputBuffer[0] = dp.d.a;
- var dp2 = diffPair<MyStruct>(MyStruct(), MyStruct.Differential(1.f));
+ var dp2 = diffPair<MyStruct>(MyStruct(0.0, 0), MyStruct.Differential(1.f));
outputBuffer[1] = dp2.d.a;
}
-} \ No newline at end of file
+}
diff --git a/tests/autodiff/generic-constructor.slang b/tests/autodiff/generic-constructor.slang
index aad9824ec..a5b098ac2 100644
--- a/tests/autodiff/generic-constructor.slang
+++ b/tests/autodiff/generic-constructor.slang
@@ -19,6 +19,16 @@ struct Impl : IFoo
{
x = v.x;
}
+
+ // We have to add this __init so that the following code can still work:
+ // Impl.Differential v0 = { (float)x };
+ // because when there is a explicit constructor defined, we will not fall back
+ // to legacy constructor. So this construction will fail.
+ [Differentiable]
+ __init(float v)
+ {
+ x = v;
+ }
}
[Differentiable]
diff --git a/tests/autodiff/generic-impl-jvp.slang b/tests/autodiff/generic-impl-jvp.slang
index e5999b4ae..000c14248 100644
--- a/tests/autodiff/generic-impl-jvp.slang
+++ b/tests/autodiff/generic-impl-jvp.slang
@@ -161,6 +161,16 @@ struct lineardvector : IDifferentiable
val.values[i] = a[i];
}
}
+
+ // Add a new constructor for dadd() function.
+ __init(Real a[N])
+ {
+ [ForceUnroll]
+ for (int i = 0; i < N; i++)
+ {
+ val.values[i] = a[i];
+ }
+ }
};
__generic<let N : int>
@@ -204,12 +214,24 @@ struct linearvector : MyLinearArithmeticType, IDifferentiable
static Differential dadd(Differential a, Differential b)
{
- return { myvector<Real, N>.dadd(a.val, b.val) };
+ // return { myvector<Real, N>.dadd(a.val, b.val) };
+ //
+ // Above code will not work because
+ // myvector<Real, N>.dadd will return dvector<T.Differential, N> type
+ // while Differential == lineardvector<N> type
+ // and the constructor of lineardvector<N> requires a vector<Real.Differential, N> type
+ // and dvector<T.Differential, N> != vector<Real.Differential, N>, though they have the
+ // same members.
+ //
+ // In our new design, generic will not be C-Style struct anymore.
+ dvector<Real.Differential, N> d = myvector<Real, N>.dadd(a.val, b.val);
+ return {d.values};
}
static Differential dmul<T: __BuiltinRealType>(T a, Differential b)
{
- return { myvector<Real, N>.dmul<T>(a, b.val) };
+ dvector<Real.Differential, N> d = myvector<Real, N>.dmul<T>(a, b.val);
+ return {d.values};
}
[ForwardDifferentiable]
diff --git a/tests/autodiff/self-differential-generic-type-synthesis.slang b/tests/autodiff/self-differential-generic-type-synthesis.slang
index 8d225dec2..7883188f6 100644
--- a/tests/autodiff/self-differential-generic-type-synthesis.slang
+++ b/tests/autodiff/self-differential-generic-type-synthesis.slang
@@ -17,7 +17,7 @@ struct Ray<let N: int> : IDifferentiable {
[numthreads(1, 1, 1)]
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
{
- Ray<4> ray = Ray<4>();
+ Ray<4> ray = Ray<4>(0.0, float4(0.0), float4(0.0));;
Ray<4>.Differential ray2;
ray.a = 1.f;
diff --git a/tests/autodiff/self-differential-type-synthesis.slang b/tests/autodiff/self-differential-type-synthesis.slang
index 7f95891c6..6faa2175a 100644
--- a/tests/autodiff/self-differential-type-synthesis.slang
+++ b/tests/autodiff/self-differential-type-synthesis.slang
@@ -17,7 +17,7 @@ struct Ray : IDifferentiable {
[numthreads(1, 1, 1)]
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
{
- Ray ray = Ray();
+ Ray ray = {};
Ray.Differential ray2;
ray.a = 1.f;
diff --git a/tests/bugs/addr-scope-fix.slang b/tests/bugs/addr-scope-fix.slang
index 8a58b7daf..3b0059417 100644
--- a/tests/bugs/addr-scope-fix.slang
+++ b/tests/bugs/addr-scope-fix.slang
@@ -1,4 +1,5 @@
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj -output-using-type
+//TEST(compute):COMPARE_COMPUTE_EX:-vk -slang -compute -shaderobj -output-using-type
//TEST_INPUT:ubuffer(data=[0 0 0], stride=4):out,name=outputBuffer
RWStructuredBuffer<float> outputBuffer;
@@ -73,4 +74,4 @@ void func(int x)
void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
{
func(4);
-} \ No newline at end of file
+}
diff --git a/tests/bugs/generic-default-value.slang b/tests/bugs/generic-default-value.slang
index 32dc07cdc..2a223e8c2 100644
--- a/tests/bugs/generic-default-value.slang
+++ b/tests/bugs/generic-default-value.slang
@@ -1,4 +1,5 @@
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj
+//TEST(compute):COMPARE_COMPUTE_EX:-vk -slang -compute -shaderobj
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
RWStructuredBuffer<int> outputBuffer;
@@ -8,6 +9,10 @@ works with a generic */
struct Check<T>
{
+ // T is not default initialize type, because it's a generic type parameter.
+ // Therefore, when we synthesize the contructor, we won't create a default value
+ // for it.
+ // __init(T v);
T v;
};
@@ -16,7 +21,7 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
{
int index = int(dispatchThreadID.x);
- Check<float> v = {};
+ Check<float> v = {0};
outputBuffer[index] = index + int(v.v);
}
diff --git a/tests/bugs/gh-4863.slang b/tests/bugs/gh-4863.slang
index e1f4e1d2d..b1de7134f 100644
--- a/tests/bugs/gh-4863.slang
+++ b/tests/bugs/gh-4863.slang
@@ -29,8 +29,8 @@ void doThing(inout Foo foo, uint2 ipos)
[numthreads(1, 1, 1)]
void computeMain(uint2 ipos : SV_DispatchThreadID)
{
- Foo foo;
+ Foo foo = {};
doThing(foo, ipos);
// BUFFER: 3
outputBuffer[0] = (int)foo.bar1;
-} \ No newline at end of file
+}
diff --git a/tests/bugs/overload-ambiguous-2.slang b/tests/bugs/overload-ambiguous-2.slang
index 46af9f091..785db7b31 100644
--- a/tests/bugs/overload-ambiguous-2.slang
+++ b/tests/bugs/overload-ambiguous-2.slang
@@ -57,7 +57,7 @@ void computeMain(uint3 threadID: SV_DispatchThreadID)
{
using namespace A;
- Struct2<10> input = {threadID.x};
+ Struct2<10> input = {{threadID.x}};
Struct2<20> output;
output = myFunc<10, 20>(input);
diff --git a/tests/compute/empty-struct2.slang b/tests/compute/empty-struct2.slang
index 303cfd234..4476bcaa1 100644
--- a/tests/compute/empty-struct2.slang
+++ b/tests/compute/empty-struct2.slang
@@ -48,7 +48,7 @@ void test<Obj : IInterface>(Obj obj)
[numthreads(4, 1, 1)]
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
{
- Empty<EmptyS> obj;
+ Empty<EmptyS> obj = {};
test(obj);
outputBuffer[dispatchThreadID.x] = dispatchThreadID.x;
}
diff --git a/tests/compute/struct-default-init.slang b/tests/compute/struct-default-init.slang
index 236fff57f..ce8979164 100644
--- a/tests/compute/struct-default-init.slang
+++ b/tests/compute/struct-default-init.slang
@@ -1,5 +1,6 @@
// struct-default-init.slang
//TEST(compute):COMPARE_COMPUTE: -shaderobj
+//TEST(compute):COMPARE_COMPUTE: -vk -shaderobj
struct Test
{
diff --git a/tests/compute/type-legalize-global-with-init.slang b/tests/compute/type-legalize-global-with-init.slang
index 573ac9849..7316cad1d 100644
--- a/tests/compute/type-legalize-global-with-init.slang
+++ b/tests/compute/type-legalize-global-with-init.slang
@@ -5,6 +5,7 @@
// resources.
//
//TEST(compute):COMPARE_COMPUTE: -shaderobj
+//TEST(compute):COMPARE_COMPUTE: -vk -shaderobj
//
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
RWStructuredBuffer<uint> outputBuffer;
diff --git a/tests/cpu-program/gfx-smoke.slang b/tests/cpu-program/gfx-smoke.slang
index 41c87ca19..3ed04877e 100644
--- a/tests/cpu-program/gfx-smoke.slang
+++ b/tests/cpu-program/gfx-smoke.slang
@@ -14,7 +14,7 @@ export __extern_cpp int main()
return -1;
}
- gfx.CommandQueueDesc queueDesc = {};
+ gfx.CommandQueueDesc queueDesc = {gfx::QueueType::Graphics};
queueDesc.type = gfx.QueueType.Graphics;
Optional<gfx.ICommandQueue> queue;
device.value.createCommandQueue(&queueDesc, queue);
@@ -42,12 +42,12 @@ export __extern_cpp int main()
device.value.createProgram2(&programDesc, program, diagBlob);
Optional<gfx.IPipelineState> pipeline;
- gfx.ComputePipelineStateDesc pipelineDesc = {};
+ gfx.ComputePipelineStateDesc pipelineDesc;
pipelineDesc.program = NativeRef<gfx.IShaderProgram>(program.value);
device.value.createComputePipelineState(&pipelineDesc, pipeline);
Optional<gfx.ITransientResourceHeap> transientHeap;
- gfx.TransientResourceHeapDesc transientHeapDesc = {};
+ gfx.TransientResourceHeapDesc transientHeapDesc;
transientHeapDesc.constantBufferDescriptorCount = 64;
transientHeapDesc.constantBufferSize = 1024;
transientHeapDesc.srvDescriptorCount = 1024;
@@ -67,7 +67,7 @@ export __extern_cpp int main()
device.value.createBufferResource(&bufferDesc, nullptr, buffer);
Optional<gfx.IResourceView> bufferView;
- gfx.ResourceViewDesc viewDesc = {};
+ gfx.ResourceViewDesc viewDesc;
viewDesc.type = gfx.ResourceViewType.UnorderedAccess;
device.value.createBufferView(buffer.value, none, &viewDesc, bufferView);
diff --git a/tests/diagnostics/interfaces/anyvalue-size-validation.slang b/tests/diagnostics/interfaces/anyvalue-size-validation.slang
index f2ed52d0c..ffe968c67 100644
--- a/tests/diagnostics/interfaces/anyvalue-size-validation.slang
+++ b/tests/diagnostics/interfaces/anyvalue-size-validation.slang
@@ -26,6 +26,6 @@ RWStructuredBuffer<uint> output;
[numthreads(4, 1, 1)]
void main()
{
- S s = S();
+ S s = S(1, 2, 3);
output[0] = test(s).a;
}
diff --git a/tests/diagnostics/mismatching-types.slang b/tests/diagnostics/mismatching-types.slang
index 15fc1d0e3..ead1d34ff 100644
--- a/tests/diagnostics/mismatching-types.slang
+++ b/tests/diagnostics/mismatching-types.slang
@@ -49,19 +49,26 @@ void main(uint3 dispatchThreadID : SV_DispatchThreadID)
// expected an expression of type 'GenericOuter<int>', got 'int'
a = 0;
+
// expected an expression of type 'GenericOuter<int>.GenericInner<int>', got 'int'
+ // explicit conversion from 'int' to 'GenericOuter<int>.GenericInner<int>' is possible
a.g = 0;
+
// expected an expression of type 'GenericOuter<int>.NonGenericInner', got 'int'
+ // explicit conversion from 'int' to 'GenericOuter<int>.GenericInner<int>' is possible
a.ng = 0;
// expected an expression of type 'GenericOuter<int>.GenericInner<int>', got 'GenericOuter<float>.GenericInner<float>'
a.g = b.g;
// expected an expression of type 'GenericOuter<int>.NonGenericInner', got 'GenericOuter<float>.NonGenericInner'
a.ng = b.ng;
// expected an expression of type 'NonGenericOuter.GenericInner<int>', got 'int'
+ // explicit conversion from 'int' to 'GenericInner<int>' is possible
c.i = 0;
// expected an expression of type 'NonGenericOuter.GenericInner<int>', got 'NonGenericOuter.GenericInner<float>'
c.i = c.f;
+
// expected an expression of type 'NonGenericOuter.GenericInner<int>.ReallyNested', got 'int'
+ // explicit conversion from 'int' to 'GenericInner<int>.ReallyNested' is possible
c.i.n = 0;
// OK
c.i.n.val = 0;
@@ -74,4 +81,4 @@ void main(uint3 dispatchThreadID : SV_DispatchThreadID)
Texture1D<int> t1 = tex;
// expected an expression of type 'Texture2D<float>', got 'Texture1D<float>'
Texture2D<float> t2 = tex;
-} \ No newline at end of file
+}
diff --git a/tests/diagnostics/mismatching-types.slang.expected b/tests/diagnostics/mismatching-types.slang.expected
index 65a6df32e..a706e30e6 100644
--- a/tests/diagnostics/mismatching-types.slang.expected
+++ b/tests/diagnostics/mismatching-types.slang.expected
@@ -3,31 +3,34 @@ standard error = {
tests/diagnostics/mismatching-types.slang(51): error 30019: expected an expression of type 'GenericOuter<int>', got 'int'
a = 0;
^
-tests/diagnostics/mismatching-types.slang(53): error 30019: expected an expression of type 'GenericOuter<int>.GenericInner<int>', got 'int'
+tests/diagnostics/mismatching-types.slang(55): error 30019: expected an expression of type 'GenericOuter<int>.GenericInner<int>', got 'int'
a.g = 0;
^
-tests/diagnostics/mismatching-types.slang(55): error 30019: expected an expression of type 'GenericOuter<int>.NonGenericInner', got 'int'
+tests/diagnostics/mismatching-types.slang(55): note: explicit conversion from 'int' to 'GenericOuter<int>.GenericInner<int>' is possible
+tests/diagnostics/mismatching-types.slang(59): error 30019: expected an expression of type 'GenericOuter<int>.NonGenericInner', got 'int'
a.ng = 0;
^
-tests/diagnostics/mismatching-types.slang(57): error 30019: expected an expression of type 'GenericOuter<int>.GenericInner<int>', got 'GenericOuter<float>.GenericInner<float>'
+tests/diagnostics/mismatching-types.slang(59): note: explicit conversion from 'int' to 'GenericOuter<int>.NonGenericInner' is possible
+tests/diagnostics/mismatching-types.slang(61): error 30019: expected an expression of type 'GenericOuter<int>.GenericInner<int>', got 'GenericOuter<float>.GenericInner<float>'
a.g = b.g;
^
-tests/diagnostics/mismatching-types.slang(59): error 30019: expected an expression of type 'GenericOuter<int>.NonGenericInner', got 'GenericOuter<float>.NonGenericInner'
+tests/diagnostics/mismatching-types.slang(63): error 30019: expected an expression of type 'GenericOuter<int>.NonGenericInner', got 'GenericOuter<float>.NonGenericInner'
a.ng = b.ng;
^~
-tests/diagnostics/mismatching-types.slang(61): error 30019: expected an expression of type 'NonGenericOuter.GenericInner<int>', got 'int'
+tests/diagnostics/mismatching-types.slang(66): error 30019: expected an expression of type 'NonGenericOuter.GenericInner<int>', got 'int'
c.i = 0;
^
-tests/diagnostics/mismatching-types.slang(63): error 30019: expected an expression of type 'NonGenericOuter.GenericInner<int>', got 'NonGenericOuter.GenericInner<float>'
+tests/diagnostics/mismatching-types.slang(68): error 30019: expected an expression of type 'NonGenericOuter.GenericInner<int>', got 'NonGenericOuter.GenericInner<float>'
c.i = c.f;
^
-tests/diagnostics/mismatching-types.slang(65): error 30019: expected an expression of type 'NonGenericOuter.GenericInner<int>.ReallyNested', got 'int'
+tests/diagnostics/mismatching-types.slang(72): error 30019: expected an expression of type 'NonGenericOuter.GenericInner<int>.ReallyNested', got 'int'
c.i.n = 0;
^
-tests/diagnostics/mismatching-types.slang(74): error 30019: expected an expression of type 'Texture1D<int>', got 'Texture1D<float>'
+tests/diagnostics/mismatching-types.slang(72): note: explicit conversion from 'int' to 'NonGenericOuter.GenericInner<int>.ReallyNested' is possible
+tests/diagnostics/mismatching-types.slang(81): error 30019: expected an expression of type 'Texture1D<int>', got 'Texture1D<float>'
Texture1D<int> t1 = tex;
^~~
-tests/diagnostics/mismatching-types.slang(76): error 30019: expected an expression of type 'Texture2D<float>', got 'Texture1D<float>'
+tests/diagnostics/mismatching-types.slang(83): error 30019: expected an expression of type 'Texture2D<float>', got 'Texture1D<float>'
Texture2D<float> t2 = tex;
^~~
}
diff --git a/tests/diagnostics/uninitialized-fields.slang b/tests/diagnostics/uninitialized-fields.slang
index f3c7b1a36..efa62cc36 100644
--- a/tests/diagnostics/uninitialized-fields.slang
+++ b/tests/diagnostics/uninitialized-fields.slang
@@ -56,16 +56,16 @@ struct Partial
// Warnings here should be a bit different
struct Implicit
{
- //CHK-DAG: warning 41021: default initializer for 'Implicit' will not initialize field 'a'
int a;
int b = 1;
- //CHK-DAG: warning 41021: default initializer for 'Implicit' will not initialize field 'c'
int c;
int d = 1 + 1;
}
int using_implicit(int x)
{
+ // no default constructor will be called, because there is no __init() synthesized for `Implicit`
+ // so no warnings will be reported on members of `Implicit`
Implicit impl;
impl.a = x;
return impl.c;
diff --git a/tests/diagnostics/variable-redeclaration.slang b/tests/diagnostics/variable-redeclaration.slang
index bbd6a07c0..d238442e8 100644
--- a/tests/diagnostics/variable-redeclaration.slang
+++ b/tests/diagnostics/variable-redeclaration.slang
@@ -37,7 +37,7 @@ int testLocalShadowing(int x)
}
// Structure fields
-
+// Note: more diagnostics will be reported here because of the constructor synthesis
struct S
{
int f;
diff --git a/tests/diagnostics/variable-redeclaration.slang.expected b/tests/diagnostics/variable-redeclaration.slang.expected
index 1998c13c8..842038180 100644
--- a/tests/diagnostics/variable-redeclaration.slang.expected
+++ b/tests/diagnostics/variable-redeclaration.slang.expected
@@ -30,6 +30,30 @@ tests/diagnostics/variable-redeclaration.slang(21): error 30200: declaration of
tests/diagnostics/variable-redeclaration.slang(20): note: see previous declaration of 'y'
int y = x;
^
+tests/diagnostics/variable-redeclaration.slang(41): error 30200: declaration of 'f' conflicts with existing declaration
+struct S
+ ^
+tests/diagnostics/variable-redeclaration.slang(41): note: see previous declaration of 'f'
+struct S
+ ^
+tests/diagnostics/variable-redeclaration.slang(43): error 39999: ambiguous reference to 'f'
+ int f;
+ ^
+tests/diagnostics/variable-redeclaration.slang(44): note 39999: candidate: float S.f
+ float f;
+ ^
+tests/diagnostics/variable-redeclaration.slang(43): note 39999: candidate: int S.f
+ int f;
+ ^
+tests/diagnostics/variable-redeclaration.slang(44): error 39999: ambiguous reference to 'f'
+ float f;
+ ^
+tests/diagnostics/variable-redeclaration.slang(44): note 39999: candidate: float S.f
+ float f;
+ ^
+tests/diagnostics/variable-redeclaration.slang(43): note 39999: candidate: int S.f
+ int f;
+ ^
tests/diagnostics/variable-redeclaration.slang(53): error 39999: ambiguous reference to 'size'
return size;
^~~~
diff --git a/tests/initializer-list/c-style-type.slang b/tests/initializer-list/c-style-type.slang
new file mode 100644
index 000000000..500bf37bb
--- /dev/null
+++ b/tests/initializer-list/c-style-type.slang
@@ -0,0 +1,44 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+struct CLike
+{
+ int x;
+ int y;
+ // compiler synthesizes:
+ // __init(int x, int y);
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+void test()
+{
+ // case 1: initialized with synthesized ctor call using legacy logic to form arguments,
+ // and `c1` is now `{0,0}`.
+ CLike c1 = {};
+
+ // case 2: initialized with legacy initializaer list logic, `c1` is now `{1,0}`:
+ CLike c2 = {1};
+
+ // case 3: initilaized with ctor call `CLike(1,2)`, `c3` is now `{1,2}`:
+ CLike c3 = {1, 2};
+
+ // BUFFER: 0
+ outputBuffer[0] = c1.x;
+ // BUFFER-NEXT: 0
+ outputBuffer[1] = c1.y;
+ // BUFFER-NEXT: 1
+ outputBuffer[2] = c2.x;
+ // BUFFER-NEXT: 0
+ outputBuffer[3] = c2.y;
+ // BUFFER-NEXT: 1
+ outputBuffer[4] = c3.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[5] = c3.y;
+}
+
+[shader("compute")]
+void computeMain()
+{
+ test();
+}
diff --git a/tests/initializer-list/default-member.slang b/tests/initializer-list/default-member.slang
new file mode 100644
index 000000000..8a6a0dc7f
--- /dev/null
+++ b/tests/initializer-list/default-member.slang
@@ -0,0 +1,35 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+struct DefaultMember {
+ int x = 0;
+ int y = 1;
+ // compiler synthesizes:
+ // __init(int x = 0, int y = 1);
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+void test()
+{
+ DefaultMember m1 = {1}; // calls `__init(1)`, initialized to `{1,1}`.
+
+ // BUFFER: 1
+ outputBuffer[0] = m1.x;
+
+ // BUFFER-NEXT: 1
+ outputBuffer[1] = m1.y;
+
+ DefaultMember m2 = {1,2}; // calls `__init(1,2)`, initialized to `{1,2}`.
+
+ // BUFFER-NEXT: 1
+ outputBuffer[2] = m2.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[3] = m2.y;
+}
+
+[shader("compute")]
+void computeMain()
+{
+ test();
+}
diff --git a/tests/initializer-list/explicit-ctor-diagnostic.slang b/tests/initializer-list/explicit-ctor-diagnostic.slang
new file mode 100644
index 000000000..a9d0e9858
--- /dev/null
+++ b/tests/initializer-list/explicit-ctor-diagnostic.slang
@@ -0,0 +1,19 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+struct ExplicitCtor
+{
+ int x;
+ int y;
+ __init(int x)
+ {
+ this.x = x;
+ this.y = 0;
+ }
+ // compiler does not synthesize any ctors.
+}
+
+void test()
+{
+ // CHECK: error 39999: too many arguments to call (got 2, expected 1)
+ ExplicitCtor e = {1, 2}; // error, no ctor matches initializer list.
+}
diff --git a/tests/initializer-list/explicit-ctor.slang b/tests/initializer-list/explicit-ctor.slang
new file mode 100644
index 000000000..c587bcce4
--- /dev/null
+++ b/tests/initializer-list/explicit-ctor.slang
@@ -0,0 +1,41 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+struct ExplicitCtor
+{
+ int x;
+ int y;
+ __init(int x)
+ {
+ this.x = x;
+ this.y = x + 5;
+ }
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+void test()
+{
+ // case 1: initialized with synthesized ctor call using legacy logic to form arguments,
+ // and `c1` is now `{0,0}`.
+ ExplicitCtor c1 = {4};
+
+ // BUFFER: 4
+ outputBuffer[0] = c1.x;
+ // BUFFER-NEXT: 9
+ outputBuffer[1] = c1.y;
+
+
+ ExplicitCtor c2 = ExplicitCtor(10);
+
+ // BUFFER: A
+ outputBuffer[2] = c2.x;
+ // BUFFER-NEXT: F
+ outputBuffer[3] = c2.y;
+}
+
+[shader("compute")]
+void computeMain()
+{
+ test();
+}
diff --git a/tests/initializer-list/extension-overload-1.slang b/tests/initializer-list/extension-overload-1.slang
new file mode 100644
index 000000000..1c3189f84
--- /dev/null
+++ b/tests/initializer-list/extension-overload-1.slang
@@ -0,0 +1,49 @@
+
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+import modulea;
+
+// Definition of the Foo struct
+// struct Foo
+// {
+// int a;
+// int b;
+// }
+
+// This test demonstrates that whether struct is a C-Style type only depends on the definition of the struct, not the extension.
+// Even we have an explicit constructor defined in extension of Foo, it is still a C-Style type.
+
+extension Foo
+{
+ __init(int a)
+ {
+ this.a = a + 5;
+ this.b = 3;
+ }
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+[shader("compute")]
+[numthreads(1, 1, 1)]
+void computeMain()
+{
+
+ // This will miss both synthesized constructor and explicit constructor in extension, but it will still fall back
+ // to legacy initializer list because Foo is a C-Style type.
+ Foo foo = {};
+ //CHECK: BUFFER: 0
+ //CHECK: BUFFER-NEXT: 0
+ outputBuffer[0] = foo.a;
+ outputBuffer[1] = foo.b;
+
+
+ // When providing 1 parameter, it will lookup for the explicit constructor in extension.
+ Foo foo1 = {1};
+ //CHECK: BUFFER: 6
+ //CHECK: BUFFER-NEXT: 3
+ outputBuffer[2] = foo1.a;
+ outputBuffer[3] = foo1.b;
+}
diff --git a/tests/initializer-list/extension-overload-2.slang b/tests/initializer-list/extension-overload-2.slang
new file mode 100644
index 000000000..3937127f4
--- /dev/null
+++ b/tests/initializer-list/extension-overload-2.slang
@@ -0,0 +1,28 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+struct Foo
+{
+ int a;
+}
+
+extension Foo
+{
+ __init(int a)
+ {
+ this.a = a + 5;
+ }
+}
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+[shader("compute")]
+[numthreads(1, 1, 1)]
+void computeMain()
+{
+ // it will prefer the explicit constructor defined in the extension instead of the synthesized one in the struct
+ Foo foo = {1.0f};
+ //CHECK: BUFFER: 6
+ outputBuffer[0] = foo.a;
+}
diff --git a/tests/initializer-list/modulea.slang b/tests/initializer-list/modulea.slang
new file mode 100644
index 000000000..48a4a5d6a
--- /dev/null
+++ b/tests/initializer-list/modulea.slang
@@ -0,0 +1,5 @@
+export struct Foo
+{
+ int a;
+ int b;
+}
diff --git a/tests/initializer-list/partial-init-diagnostic.slang b/tests/initializer-list/partial-init-diagnostic.slang
new file mode 100644
index 000000000..ea3acb2c7
--- /dev/null
+++ b/tests/initializer-list/partial-init-diagnostic.slang
@@ -0,0 +1,19 @@
+//DISABLE_DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+struct PartialInit
+{
+ int x = 1;
+ int y;
+ // compiler synthesizes:
+ // __init(int x, int y);
+}
+
+void test()
+{
+ // TODO: Because we have a legacy logic that will always convert the one arugment ctor call to
+ // initializer list, and that initializer list will fall back to the legacy C-Style initialization.
+ // We need to remove that logic.
+
+ // CHECK: error 33070: expected a function, got 'typeof(PartialInit)'
+ PartialInit p = PartialInit(2); // error, no ctor match.
+}
diff --git a/tests/initializer-list/partial-init.slang b/tests/initializer-list/partial-init.slang
new file mode 100644
index 000000000..55f3816fb
--- /dev/null
+++ b/tests/initializer-list/partial-init.slang
@@ -0,0 +1,47 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+struct PartialInit {
+ // warning: not all members are initialized.
+ // members should either be all-uninitialized or all-initialized with
+ // default expr.
+ int x;
+ int y = 1;
+ // compiler synthesizes:
+ // __init(int x, int y = 1);
+}
+
+struct PartialInit2 {
+ int x = 1;
+ int y;
+ // __init(int x, int y);
+}
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+void test()
+{
+ PartialInit p1 = {2}; // calls `__init`, result is `{2,1}`.
+ // BUFFER: 2
+ outputBuffer[0] = p1.x;
+ // BUFFER-NEXT: 1
+ outputBuffer[1] = p1.y;
+
+
+ PartialInit p2 = {2, 3}; // calls `__init`, result is {2, 3}
+ // BUFFER-NEXT: 2
+ outputBuffer[2] = p2.x;
+ // BUFFER-NEXT: 3
+ outputBuffer[3] = p2.y;
+
+ PartialInit2 p3 = {4, 5}; // calls `__init`, result is {4, 5}
+ // BUFFER-NEXT: 4
+ outputBuffer[4] = p3.x;
+ // BUFFER-NEXT: 5
+ outputBuffer[5] = p3.y;
+}
+
+[shader("compute")]
+void computeMain()
+{
+ test();
+}
diff --git a/tests/initializer-list/struct-visibility-1.slang b/tests/initializer-list/struct-visibility-1.slang
new file mode 100644
index 000000000..691e8c991
--- /dev/null
+++ b/tests/initializer-list/struct-visibility-1.slang
@@ -0,0 +1,105 @@
+
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+public struct Visibility
+{
+ internal int x = 1;
+ public int y = 5;
+
+ int getX() { return x; }
+}
+
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+void test(inout uint index)
+{
+ Visibility t1 = {}; // OK, initialized to {1,5} via ctor call.
+ // BUFFER: 1
+ outputBuffer[index++] = t1.getX();
+ // BUFFER-NEXT: 5
+ outputBuffer[index++] = t1.y;
+
+ Visibility t2 = {1}; // OK, initialized to {1,1} via ctor call.
+ // BUFFER-NEXT: 1
+ outputBuffer[index++] = t2.getX();
+ // BUFFER-NEXT: 1
+ outputBuffer[index++] = t2.y;
+}
+
+internal struct Visibility2
+{
+ // Visibility3 type is considered as C-style struct.
+ // Because all members have the same visibility as the type.
+ // Therefore we will attempt the legacy fallback logic for
+ // initializer-list syntax.
+ // Note that c-style structs can still have init exprs on members.
+ internal int x;
+ internal int y = 2;
+ // compiler synthesizes:
+ // internal __init(int x, int y = 2);
+}
+
+internal void test2(inout uint index)
+{
+ Visibility2 t = {3, 4}; // OK, initialized to {3,4} via ctor call.
+ // BUFFER-NEXT: 3
+ outputBuffer[index++] = t.x;
+ // BUFFER-NEXT: 4
+ outputBuffer[index++] = t.y;
+
+ Visibility2 t1 = {1}; // OK, initialized to {1,2} via ctor call.
+ // BUFFER-NEXT: 1
+ outputBuffer[index++] = t1.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[index++] = t1.y;
+
+ Visibility2 t2 = {}; // OK, initialized to {0, 2} via legacy logic.
+ // BUFFER-NEXT: 0
+ outputBuffer[index++] = t2.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[index++] = t2.y;
+}
+
+internal struct Visibility3
+{
+ // Visibility4 type is considered as C-style struct.
+ // And we still synthesize a ctor for member initialization.
+ // Because Visibility4 has no public members, the synthesized
+ // ctor will take 0 arguments.
+ internal int x = 1;
+ internal int y = 2;
+ // compiler synthesizes:
+ // internal __init(int x = 1, int y = 2);
+}
+
+internal void test3(inout uint index)
+{
+ Visibility3 t = {0, 0}; // OK, initialized to {0,0} via ctor call.
+ // BUFFER-NEXT: 0
+ outputBuffer[index++] = t.x;
+ // BUFFER-NEXT: 0
+ outputBuffer[index++] = t.y;
+
+ Visibility3 t1 = {3}; // OK, initialized to {3,2} via ctor call.
+ // BUFFER-NEXT: 3
+ outputBuffer[index++] = t1.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[index++] = t1.y;
+
+ Visibility3 t2 = {}; // OK, initialized to {1,2} via ctor call.
+ // BUFFER-NEXT: 1
+ outputBuffer[index++] = t2.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[index++] = t2.y;
+}
+
+[shader("compute")]
+void computeMain()
+{
+ uint index = 0;
+ test(index);
+ test2(index);
+ test3(index);
+}
diff --git a/tests/initializer-list/struct-visibility-diagnostic-1.slang b/tests/initializer-list/struct-visibility-diagnostic-1.slang
new file mode 100644
index 000000000..ab11933ae
--- /dev/null
+++ b/tests/initializer-list/struct-visibility-diagnostic-1.slang
@@ -0,0 +1,21 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+public struct Visibility
+{
+ internal int x;
+ public int y = 0;
+ // the compiler does not synthesize any ctor.
+ // the compiler will try to synthesize:
+ // public __init(int y);
+ // but then it will find that `x` cannot be initialized.
+ // so this synthesis will fail and no ctor will be added
+ // to the type.
+}
+
+void test()
+{
+ // CHECK: error 39999: too many arguments to call (got 2, expected 1)
+ Visibility t1 = {1, 2}; // error, no matching ctor
+}
+
+
diff --git a/tests/initializer-list/struct-visibility-diagnostic-2.slang b/tests/initializer-list/struct-visibility-diagnostic-2.slang
new file mode 100644
index 000000000..a3255de5e
--- /dev/null
+++ b/tests/initializer-list/struct-visibility-diagnostic-2.slang
@@ -0,0 +1,21 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+public struct Visibility
+{
+ internal int x;
+ public int y = 5;
+ // the compiler does not synthesize any ctor.
+ // the compiler will try to synthesize:
+ // public __init(int y);
+ // but then it will find that `x` cannot be initialized.
+ // so this synthesis will fail and no ctor will be added
+ // to the type.
+}
+
+void test()
+{
+ // CHECK: warning 41021: default initializer for 'Visibility' will not initialize field 'x'
+ Visibility t1 = {};
+}
+
+
diff --git a/tests/initializer-list/struct-visibility-diagnostic-3.slang b/tests/initializer-list/struct-visibility-diagnostic-3.slang
new file mode 100644
index 000000000..75ac5919d
--- /dev/null
+++ b/tests/initializer-list/struct-visibility-diagnostic-3.slang
@@ -0,0 +1,21 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+public struct Visibility
+{
+ internal int x;
+ public int y;
+ // the compiler does not synthesize any ctor.
+ // the compiler will try to synthesize:
+ // public __init(int y);
+ // but then it will find that `x` cannot be initialized.
+ // so this synthesis will fail and no ctor will be added
+ // to the type.
+}
+
+void test()
+{
+ //CHECK: error 39999: not enough arguments to call (got 0, expected 1)
+ Visibility t1 = {};
+}
+
+
diff --git a/tests/initializer-list/struct-visibility-diagnostic-4.slang b/tests/initializer-list/struct-visibility-diagnostic-4.slang
new file mode 100644
index 000000000..9bc3a76f0
--- /dev/null
+++ b/tests/initializer-list/struct-visibility-diagnostic-4.slang
@@ -0,0 +1,16 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+public struct Visibility
+{
+ internal int x = 1;
+ public int y = 5;
+ // compiler synthesizes:
+ // public __init(int y = 0);
+}
+
+void test()
+{
+ //CHECK: error 39999: too many arguments to call (got 2, expected 1)
+ Visibility t1 = {1, 2};
+}
+
diff --git a/tests/initializer-list/unintialize-warning.slang b/tests/initializer-list/unintialize-warning.slang
new file mode 100644
index 000000000..b8f2867ee
--- /dev/null
+++ b/tests/initializer-list/unintialize-warning.slang
@@ -0,0 +1,85 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+struct CLike
+{
+ int x;
+ int y;
+ // compiler synthesizes:
+ // __init(int x, int y);
+}
+
+struct ExplicitCtor
+{
+ int x;
+ int y;
+ __init(int x)
+ {
+ this.x = x;
+ this.y = 0;
+ }
+ // compiler does not synthesize any ctors.
+}
+
+struct DefaultMember {
+ int x = 0;
+ int y = 1;
+ // compiler synthesizes:
+ // __init(int x = 0, int y = 1);
+}
+
+struct PartialInit1 {
+ int x;
+ int y = 1;
+ // compiler synthesizes:
+ // __init(int x, int y = 1);
+}
+
+struct PartialInit2 {
+ int x = 1;
+ int y; // warning: not all members are initialized.
+ // compiler synthesizes:
+ // __init(int x, int y);
+}
+
+void func1(CLike c)
+{
+}
+
+void func2(ExplicitCtor e)
+{
+}
+
+void func3(DefaultMember d)
+{
+}
+
+void func4(PartialInit1 p)
+{
+}
+
+void func5(PartialInit2 p)
+{
+}
+
+void test()
+{
+ CLike c; // `c` is uninitialized.
+ // CHECK: warning 41016: use of uninitialized variable 'c'
+ func1(c);
+
+ ExplicitCtor e; // `e` is uninitialized.
+ // CHECK: warning 41016: use of uninitialized variable 'e'
+ func2(e);
+
+ DefaultMember d; // `d` is uninitialized.
+ // CHECK: warning 41016: use of uninitialized variable 'd'
+ func3(d);
+
+ PartialInit1 p1; // `p` is uninitialized.
+ // CHECK: warning 41016: use of uninitialized variable 'p1'
+ func4(p1);
+
+ PartialInit2 p2; // `p` is uninitialized.
+ // CHECK: warning 41016: use of uninitialized variable 'p2'
+ func5(p2);
+}
diff --git a/tests/language-feature/extensions/interface-extension.slang b/tests/language-feature/extensions/interface-extension.slang
index 50bbbe22a..88ef908d8 100644
--- a/tests/language-feature/extensions/interface-extension.slang
+++ b/tests/language-feature/extensions/interface-extension.slang
@@ -3,6 +3,7 @@
// Test that an `extension` applied to an interface type works as users expect
//TEST(compute):COMPARE_COMPUTE: -shaderobj
+//TEST(compute):COMPARE_COMPUTE: -vk -shaderobj
interface ICounter
{
diff --git a/tests/language-feature/extensions/this-in-extension.slang b/tests/language-feature/extensions/this-in-extension.slang
index 374eabe6f..f9cc31fca 100644
--- a/tests/language-feature/extensions/this-in-extension.slang
+++ b/tests/language-feature/extensions/this-in-extension.slang
@@ -3,6 +3,7 @@
// Test that an `This` type works correctly when there is an extension.
//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -shaderobj
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -shaderobj -vk
interface IFoo
{
@@ -31,7 +32,7 @@ RWStructuredBuffer<int> outputBuffer;
[numthreads(1, 1, 1)]
void computeMain(int3 dispatchThreadID : SV_DispatchThreadID)
{
- FooImpl foo;
+ FooImpl foo = {};
var ident = foo.getIdentity();
// CHECK: 1
outputBuffer[0] = ident.v;
diff --git a/tests/language-feature/generics/struct-generic-value-param.slang b/tests/language-feature/generics/struct-generic-value-param.slang
index 7b3b847d5..df79b834d 100644
--- a/tests/language-feature/generics/struct-generic-value-param.slang
+++ b/tests/language-feature/generics/struct-generic-value-param.slang
@@ -17,6 +17,7 @@
// when trying out the feature.
//TEST(compute):COMPARE_COMPUTE: -shaderobj
+//TEST(compute):COMPARE_COMPUTE: -vk -shaderobj
import struct_generic_value_param_import;
diff --git a/tests/language-feature/inheritance/derived-struct-init-list.slang b/tests/language-feature/inheritance/derived-struct-init-list.slang
index 978fea904..51d3a9b6d 100644
--- a/tests/language-feature/inheritance/derived-struct-init-list.slang
+++ b/tests/language-feature/inheritance/derived-struct-init-list.slang
@@ -1,6 +1,7 @@
// derived-struct-init-list.slang
//TEST(compute):COMPARE_COMPUTE:
+//TEST(compute):COMPARE_COMPUTE: -vk -shaderobj
// Test that use of an initializer list (especially
// an empty initializer list) is still possible
diff --git a/tests/language-feature/inheritance/struct-inherit-interface-requirement.slang b/tests/language-feature/inheritance/struct-inherit-interface-requirement.slang
index fbf3405ff..84446aec3 100644
--- a/tests/language-feature/inheritance/struct-inherit-interface-requirement.slang
+++ b/tests/language-feature/inheritance/struct-inherit-interface-requirement.slang
@@ -1,6 +1,7 @@
// struct-inherit-interface-requirement.slang
//TEST(compute):COMPARE_COMPUTE: -shaderobj
+//TEST(compute):COMPARE_COMPUTE: -vk -shaderobj
// Test that a `struct` type can use an inherited
// member to satisfy an interface requirement.
diff --git a/tests/language-feature/inheritance/struct-inheritance.slang b/tests/language-feature/inheritance/struct-inheritance.slang
index e50b1268b..d1611ddfc 100644
--- a/tests/language-feature/inheritance/struct-inheritance.slang
+++ b/tests/language-feature/inheritance/struct-inheritance.slang
@@ -1,6 +1,7 @@
// struct-inheritance.slang
//TEST(compute):COMPARE_COMPUTE: -shaderobj
+//TEST(compute):COMPARE_COMPUTE: -vk -shaderobj
// Test that we can define a `struct` type
// that inherits from another `struct`.
diff --git a/tests/language-feature/initializer-lists/inheritance-generic.slang b/tests/language-feature/initializer-lists/inheritance-generic.slang
index c916178b8..d5b923afe 100644
--- a/tests/language-feature/initializer-lists/inheritance-generic.slang
+++ b/tests/language-feature/initializer-lists/inheritance-generic.slang
@@ -19,7 +19,10 @@ RWStructuredBuffer<int> result;
[numthreads(1, 1, 1)]
void computeMain()
{
- Derived<3> d;
+ // Previously, this test is just test we can handle the base constructor invoke correctly,
+ // so we don't construct the Derived object, since #6058, there will not be implicit constructor
+ // to construct the struct, we will have to invoke the constructor explicitly.
+ Derived<3> d = {1,1,1};
// BUFFER: 1
result[0] = d.a;
diff --git a/tests/language-feature/interfaces/zero-init-interface.slang b/tests/language-feature/interfaces/zero-init-interface.slang
index ee38f4d83..ed3b1eaa4 100644
--- a/tests/language-feature/interfaces/zero-init-interface.slang
+++ b/tests/language-feature/interfaces/zero-init-interface.slang
@@ -1,6 +1,7 @@
// Test that we can zero-init a struct with interface typed member.
//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER): -shaderobj
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER): -vk -shaderobj
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;
diff --git a/tests/language-feature/overloaded-subscript.slang b/tests/language-feature/overloaded-subscript.slang
index f396f4f66..68ad1111a 100644
--- a/tests/language-feature/overloaded-subscript.slang
+++ b/tests/language-feature/overloaded-subscript.slang
@@ -38,7 +38,7 @@ RWStructuredBuffer<int> outputBuffer;
[numthreads(1,1,1)]
void computeMain()
{
- MyArray<int> arr = {};
+ MyArray<int> arr = {{1, 2, 3, 4}};
arr[0] = 1;
arr[1] = 2;
// CHECK: 1
diff --git a/tests/language-feature/properties/property-in-interface.slang b/tests/language-feature/properties/property-in-interface.slang
index 9f9e7ff50..2ef050624 100644
--- a/tests/language-feature/properties/property-in-interface.slang
+++ b/tests/language-feature/properties/property-in-interface.slang
@@ -1,6 +1,6 @@
// property-in-interface.slang
-//TEST(compute):COMPARE_COMPUTE: -shaderobj
+//TEST(compute):COMPARE_COMPUTE: -shaderobj -vk
// Test that interfaces can include property declarations.
diff --git a/tests/language-feature/struct-field-initializers/struct-field-initializer-import.slang b/tests/language-feature/struct-field-initializers/struct-field-initializer-import.slang
index 6c8b6fee1..1478fae0b 100644
--- a/tests/language-feature/struct-field-initializers/struct-field-initializer-import.slang
+++ b/tests/language-feature/struct-field-initializers/struct-field-initializer-import.slang
@@ -15,12 +15,12 @@ void modifyOut(out DefaultStructNoInit2 noInit2)
[numthreads(1, 1, 1)]
void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
{
- DefaultStructNoInit noInit;
- DefaultStructNoInit2 noInit2;
+ DefaultStructNoInit noInit = {};
+ DefaultStructNoInit2 noInit2 = {};
modifyOut(noInit2);
// BUF: 1
outputBuffer[0] = true
&& noInit.data0 == 2
&& noInit2.data0 == 2
;
-} \ No newline at end of file
+}
diff --git a/tests/language-feature/struct-field-initializers/struct-field-initializer-inherited-chain.slang b/tests/language-feature/struct-field-initializers/struct-field-initializer-inherited-chain.slang
index ef21a452f..e6f856a21 100644
--- a/tests/language-feature/struct-field-initializers/struct-field-initializer-inherited-chain.slang
+++ b/tests/language-feature/struct-field-initializers/struct-field-initializer-inherited-chain.slang
@@ -29,10 +29,10 @@ struct DefaultStruct_top : DefaultStruct_middle2
[numthreads(1, 1, 1)]
void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
{
- DefaultStruct_bottom s1;
- DefaultStruct_middle1 s2;
- DefaultStruct_middle2 s3;
- DefaultStruct_top s4;
+ DefaultStruct_bottom s1 = {};
+ DefaultStruct_middle1 s2 = {};
+ DefaultStruct_middle2 s3 = {};
+ DefaultStruct_top s4 = {};
// BUF: 1
outputBuffer[0] = true
@@ -50,4 +50,4 @@ void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
&& s4.data2 == 1
&& s4.data3 == 1
;
-} \ No newline at end of file
+}
diff --git a/tests/language-feature/struct-field-initializers/struct-field-initializer-inherited.slang b/tests/language-feature/struct-field-initializers/struct-field-initializer-inherited.slang
index 8edb98447..954a1edbe 100644
--- a/tests/language-feature/struct-field-initializers/struct-field-initializer-inherited.slang
+++ b/tests/language-feature/struct-field-initializers/struct-field-initializer-inherited.slang
@@ -46,10 +46,10 @@ struct DefaultStruct4 : DefaultStruct_base
[numthreads(1, 1, 1)]
void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
{
- DefaultStruct1 s1;
+ DefaultStruct1 s1 = {};
DefaultStruct2 s2;
DefaultStruct3 s3;
- DefaultStruct4 s4;
+ DefaultStruct4 s4 = {};
// BUF: 1
outputBuffer[0] = true
&& s1.data0 == 1
@@ -63,4 +63,4 @@ void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
&& s4.data0 == 1
&& s4.data1 == 1
;
-} \ No newline at end of file
+}
diff --git a/tests/language-feature/struct-field-initializers/struct-field-initializer-static.slang b/tests/language-feature/struct-field-initializers/struct-field-initializer-static.slang
index b2ed006be..d6f9d3612 100644
--- a/tests/language-feature/struct-field-initializers/struct-field-initializer-static.slang
+++ b/tests/language-feature/struct-field-initializers/struct-field-initializer-static.slang
@@ -23,7 +23,7 @@ struct DefaultStructNoInit : DefaultStructNoInit_base
void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
{
DefaultStructNoInit::data4 = 0;
- DefaultStructNoInit noInit;
+ DefaultStructNoInit noInit = {};
// BUF: 1
outputBuffer[0] = true
&& noInit.data0 == 2
@@ -32,4 +32,4 @@ void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
&& noInit.data3 == 2
&& noInit.data4 == 0;
;
-} \ No newline at end of file
+}
diff --git a/tests/language-feature/types/is-on-type.slang b/tests/language-feature/types/is-on-type.slang
index 728f759ad..35b0a3b23 100644
--- a/tests/language-feature/types/is-on-type.slang
+++ b/tests/language-feature/types/is-on-type.slang
@@ -1,5 +1,6 @@
//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-slang -compute
+//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-slang -compute -vk
// Test that `is` operator works on generic type param.
@@ -39,7 +40,7 @@ func test<T : I>(T t) -> int
[numthreads(1,1, 1)]
void computeMain()
{
- B b;
+ B b = {};
// CHECK: 2
outputBuffer[0] = test(b);
}
diff --git a/tests/language-feature/zero-initialize/IDefaultExplicit-wrapper-type.slang b/tests/language-feature/zero-initialize/IDefaultExplicit-wrapper-type.slang
index c2781d3eb..a01961674 100644
--- a/tests/language-feature/zero-initialize/IDefaultExplicit-wrapper-type.slang
+++ b/tests/language-feature/zero-initialize/IDefaultExplicit-wrapper-type.slang
@@ -1,11 +1,11 @@
-//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
// CHECK: {{.* }}= 0;
// CHECK-NOT: {{.* }}= 0;
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl
-//TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -profile sm_6_2 -xslang -DDX12
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl
+//DISABLE_TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -profile sm_6_2 -xslang -DDX12
//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;
diff --git a/tests/language-feature/zero-initialize/IDefaultExplicit.slang b/tests/language-feature/zero-initialize/IDefaultExplicit.slang
index b196335e9..c0001e8a9 100644
--- a/tests/language-feature/zero-initialize/IDefaultExplicit.slang
+++ b/tests/language-feature/zero-initialize/IDefaultExplicit.slang
@@ -1,10 +1,10 @@
-//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
// CHECK-COUNT-6: {{.* }}= 0U;
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl
-//TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -profile sm_6_2 -xslang -DDX12
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl
+//DISABLE_TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -profile sm_6_2 -xslang -DDX12
//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;
diff --git a/tests/language-feature/zero-initialize/IDefaultExplicitGenerics.slang b/tests/language-feature/zero-initialize/IDefaultExplicitGenerics.slang
index 5b17a908b..9f6b8c460 100644
--- a/tests/language-feature/zero-initialize/IDefaultExplicitGenerics.slang
+++ b/tests/language-feature/zero-initialize/IDefaultExplicitGenerics.slang
@@ -1,10 +1,10 @@
-//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
// CHECK: vec4(0.0
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl
-//TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -profile sm_6_2
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl
+//DISABLE_TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -profile sm_6_2
//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;
diff --git a/tests/language-feature/zero-initialize/generic.slang b/tests/language-feature/zero-initialize/generic.slang
index 25f52238c..dc2d5d608 100644
--- a/tests/language-feature/zero-initialize/generic.slang
+++ b/tests/language-feature/zero-initialize/generic.slang
@@ -1,7 +1,7 @@
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl -xslang -zero-initialize
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl -xslang -zero-initialize
-//TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -profile sm_6_2 -xslang -zero-initialize -xslang -DDX12
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -profile sm_6_2 -xslang -zero-initialize -xslang -DDX12
//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;
diff --git a/tests/language-feature/zero-initialize/missing-zero-init.slang b/tests/language-feature/zero-initialize/missing-zero-init.slang
index f9d715e10..a3deeabe3 100644
--- a/tests/language-feature/zero-initialize/missing-zero-init.slang
+++ b/tests/language-feature/zero-initialize/missing-zero-init.slang
@@ -1,5 +1,5 @@
-//TEST:SIMPLE(filecheck=CHECK): -target hlsl -stage compute -entry computeMain
-//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target hlsl -stage compute -entry computeMain
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
// CHECK-NOT: {{.* }}= 0;
// CHECK-NOT: return 0;
diff --git a/tests/language-feature/zero-initialize/rayquery.slang b/tests/language-feature/zero-initialize/rayquery.slang
index 6c48d3c65..72309b770 100644
--- a/tests/language-feature/zero-initialize/rayquery.slang
+++ b/tests/language-feature/zero-initialize/rayquery.slang
@@ -1,5 +1,5 @@
-//TEST:SIMPLE(filecheck=HLSL): -target hlsl -stage compute -entry computeMain -zero-initialize
-//TEST:SIMPLE(filecheck=GLSL): -target glsl -stage compute -entry computeMain -zero-initialize
+//DISABLE_TEST:SIMPLE(filecheck=HLSL): -target hlsl -stage compute -entry computeMain -zero-initialize
+//DISABLE_TEST:SIMPLE(filecheck=GLSL): -target glsl -stage compute -entry computeMain -zero-initialize
// HLSL-NOT: RayQuery{{.*}} {{.*}} =
// GLSL-NOT: rayQueryEXT {{.*}} =
diff --git a/tests/language-feature/zero-initialize/regular.slang b/tests/language-feature/zero-initialize/regular.slang
index 5627762c3..462a436b2 100644
--- a/tests/language-feature/zero-initialize/regular.slang
+++ b/tests/language-feature/zero-initialize/regular.slang
@@ -1,7 +1,7 @@
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl -xslang -zero-initialize
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl -xslang -zero-initialize
-//TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -profile sm_6_2 -xslang -zero-initialize -xslang -DDX12
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -profile sm_6_2 -xslang -zero-initialize -xslang -DDX12
//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;
diff --git a/tests/language-feature/zero-initialize/shared-memory.slang b/tests/language-feature/zero-initialize/shared-memory.slang
index 39243f796..401009eda 100644
--- a/tests/language-feature/zero-initialize/shared-memory.slang
+++ b/tests/language-feature/zero-initialize/shared-memory.slang
@@ -1,5 +1,5 @@
-//TEST:SIMPLE(filecheck=HLSL): -target hlsl -stage compute -entry computeMain -zero-initialize
-//TEST:SIMPLE(filecheck=GLSL): -target glsl -stage compute -entry computeMain -zero-initialize
+//DISABLE_TEST:SIMPLE(filecheck=HLSL): -target hlsl -stage compute -entry computeMain -zero-initialize
+//DISABLE_TEST:SIMPLE(filecheck=GLSL): -target glsl -stage compute -entry computeMain -zero-initialize
RWStructuredBuffer<uint> outputBuffer;
diff --git a/tests/language-feature/zero-initialize/static-struct-field-init-list.slang b/tests/language-feature/zero-initialize/static-struct-field-init-list.slang
index e40ca7e56..ca9f59b5e 100644
--- a/tests/language-feature/zero-initialize/static-struct-field-init-list.slang
+++ b/tests/language-feature/zero-initialize/static-struct-field-init-list.slang
@@ -1,4 +1,4 @@
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
RWStructuredBuffer<uint> outputBuffer;
diff --git a/tests/language-feature/zero-initialize/static-struct-field-init.slang b/tests/language-feature/zero-initialize/static-struct-field-init.slang
index ad2db5027..566cd2f1d 100644
--- a/tests/language-feature/zero-initialize/static-struct-field-init.slang
+++ b/tests/language-feature/zero-initialize/static-struct-field-init.slang
@@ -1,7 +1,7 @@
-//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain -zero-initialize
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain -zero-initialize
// CHECK: {{.* }}= 0U;
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
RWStructuredBuffer<uint> outputBuffer;
diff --git a/tests/language-feature/zero-initialize/struct-array-some-member-missing-init.slang b/tests/language-feature/zero-initialize/struct-array-some-member-missing-init.slang
index cdd3f703f..1be88862f 100644
--- a/tests/language-feature/zero-initialize/struct-array-some-member-missing-init.slang
+++ b/tests/language-feature/zero-initialize/struct-array-some-member-missing-init.slang
@@ -1,5 +1,5 @@
-//TEST:SIMPLE(filecheck=CHECK): -target hlsl -stage compute -entry computeMain -xslang -zero-initialize
-//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain -xslang -zero-initialize
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target hlsl -stage compute -entry computeMain -xslang -zero-initialize
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain -xslang -zero-initialize
// CHECK-NOT: {{.* }}= 0;
diff --git a/tests/language-feature/zero-initialize/struct-array.slang b/tests/language-feature/zero-initialize/struct-array.slang
index 1f1b8eede..6454cd493 100644
--- a/tests/language-feature/zero-initialize/struct-array.slang
+++ b/tests/language-feature/zero-initialize/struct-array.slang
@@ -1,7 +1,7 @@
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl -xslang -zero-initialize
-//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl -xslang -zero-initialize
-//TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -xslang -zero-initialize
//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;
diff --git a/tests/language-feature/zero-initialize/struct-no-zero-init.slang b/tests/language-feature/zero-initialize/struct-no-zero-init.slang
index 3a4a5f945..f7d8722ca 100644
--- a/tests/language-feature/zero-initialize/struct-no-zero-init.slang
+++ b/tests/language-feature/zero-initialize/struct-no-zero-init.slang
@@ -1,5 +1,5 @@
-//TEST:SIMPLE(filecheck=CHECK): -target hlsl -stage compute -entry computeMain
-//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target hlsl -stage compute -entry computeMain
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
// CHECK-NOT: {{.* }}= 0;
diff --git a/tests/language-feature/zero-initialize/struct-some-member-init-missing-zero-init.slang b/tests/language-feature/zero-initialize/struct-some-member-init-missing-zero-init.slang
index 2b584ad00..903afb144 100644
--- a/tests/language-feature/zero-initialize/struct-some-member-init-missing-zero-init.slang
+++ b/tests/language-feature/zero-initialize/struct-some-member-init-missing-zero-init.slang
@@ -1,5 +1,5 @@
-//TEST:SIMPLE(filecheck=CHECK): -target hlsl -stage compute -entry computeMain
-//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target hlsl -stage compute -entry computeMain
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
// CHECK-NOT: {{.* }}= 0;
diff --git a/tests/language-feature/zero-initialize/struct-some-zero-init.slang b/tests/language-feature/zero-initialize/struct-some-zero-init.slang
index 9bbb1f49e..b2a1be8a3 100644
--- a/tests/language-feature/zero-initialize/struct-some-zero-init.slang
+++ b/tests/language-feature/zero-initialize/struct-some-zero-init.slang
@@ -1,10 +1,10 @@
-//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain -zero-initialize
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain -zero-initialize
// CHECK-COUNT-2: {{.* }}= 0;
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl -xslang -zero-initialize
-//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl -xslang -zero-initialize
-//TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -emit-spirv-directly -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -xslang -zero-initialize
//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;
diff --git a/tests/language-feature/zero-initialize/struct.slang b/tests/language-feature/zero-initialize/struct.slang
index efb1d8fc3..bd6b399e0 100644
--- a/tests/language-feature/zero-initialize/struct.slang
+++ b/tests/language-feature/zero-initialize/struct.slang
@@ -1,9 +1,9 @@
-//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain -zero-initialize
+//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain -zero-initialize
// CHECK-COUNT-3: {{.* }}= 0;
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
-//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl -xslang -zero-initialize
-//TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -entry computeMain -allow-glsl -xslang -zero-initialize
+//DISABLE_TEST(smoke,compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-dx12 -use-dxil -compute -entry computeMain -allow-glsl -xslang -zero-initialize
//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;
diff --git a/tests/pipeline/rasterization/mesh/hlsl-syntax.slang.glsl b/tests/pipeline/rasterization/mesh/hlsl-syntax.slang.glsl
index 01e29f879..0d7a201ef 100644
--- a/tests/pipeline/rasterization/mesh/hlsl-syntax.slang.glsl
+++ b/tests/pipeline/rasterization/mesh/hlsl-syntax.slang.glsl
@@ -2,27 +2,40 @@
#extension GL_EXT_mesh_shader : require
layout(row_major) uniform;
layout(row_major) buffer;
-const vec3 colors_0[3] = { vec3(1.0, 1.0, 0.0), vec3(0.0, 1.0, 1.0), vec3(1.0, 0.0, 1.0) };
-const vec2 positions_0[3] = { vec2(0.0, -0.5), vec2(0.5, 0.5), vec2(-0.5, 0.5) };
-layout(location = 0)
-out vec3 verts_color_0[3];
out gl_MeshPerVertexEXT
{
vec4 gl_Position;
} gl_MeshVerticesEXT[3];
+const vec3 colors_0[3] = { vec3(1.0, 1.0, 0.0), vec3(0.0, 1.0, 1.0), vec3(1.0, 0.0, 1.0) };
+const vec2 positions_0[3] = { vec2(0.0, -0.5), vec2(0.5, 0.5), vec2(-0.5, 0.5) };
+
+struct Vertex_0
+{
+ vec4 pos_0;
+ vec3 color_0;
+};
+
+Vertex_0 Vertex_x24init_0(vec4 pos_1, vec3 color_1)
+{
+ Vertex_0 _S1;
+
+ _S1.pos_0 = pos_1;
+ _S1.color_0 = color_1;
+ return _S1;
+}
+layout(location = 0)
+out vec3 verts_color_0[3];
out uvec3 gl_PrimitiveTriangleIndicesEXT[1];
void foo_0(uint _S2)
{
if(_S2 < 3U)
{
- gl_MeshVerticesEXT[_S2].gl_Position = vec4(positions_0[_S2], 0.0, 1.0);
- verts_color_0[_S2] = colors_0[_S2];
- }
- else
- {
+ Vertex_0 _S3 = Vertex_x24init_0(vec4(positions_0[_S2], 0.0, 1.0), colors_0[_S2]);
+ gl_MeshVerticesEXT[_S2].gl_Position = _S3.pos_0;
+ verts_color_0[_S2] = _S3.color_0;
}
return;
}
@@ -39,8 +52,5 @@ void main()
{
gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(0U, 1U, 2U);
}
- else
- {
- }
return;
}
diff --git a/tests/pipeline/ray-tracing/trace-ray-inline.slang.hlsl b/tests/pipeline/ray-tracing/trace-ray-inline.slang.hlsl
index 4ed4c9966..df78f3c79 100644
--- a/tests/pipeline/ray-tracing/trace-ray-inline.slang.hlsl
+++ b/tests/pipeline/ray-tracing/trace-ray-inline.slang.hlsl
@@ -2,7 +2,11 @@
#ifdef SLANG_HLSL_ENABLE_NVAPI
#include "nvHLSLExtns.h"
#endif
-#pragma warning(disable: 3557)
+
+#ifndef __DXC_VERSION_MAJOR
+// warning X3557: loop doesn't seem to do anything, forcing loop to unroll
+#pragma warning(disable : 3557)
+#endif
struct SLANG_ParameterGroup_C_0
{
@@ -23,21 +27,45 @@ RaytracingAccelerationStructure myAccelerationStructure_0 : register(t0);
RWStructuredBuffer<int > resultBuffer_0 : register(u0);
-struct MyProceduralHitAttrs_0
+struct MyRayPayload_0
{
int value_0;
};
-bool myProceduralIntersection_0(inout float tHit_0, inout MyProceduralHitAttrs_0 hitAttrs_0)
+MyRayPayload_0 MyRayPayload_x24init_0(int value_1)
{
- return true;
+ MyRayPayload_0 _S1;
+ _S1.value_0 = value_1;
+ return _S1;
}
-struct MyRayPayload_0
+RayDesc RayDesc_x24init_0(float3 Origin_0, float TMin_0, float3 Direction_0, float TMax_0)
+{
+ RayDesc _S2;
+ _S2.Origin = Origin_0;
+ _S2.TMin = TMin_0;
+ _S2.Direction = Direction_0;
+ _S2.TMax = TMax_0;
+ return _S2;
+}
+
+struct MyProceduralHitAttrs_0
{
- int value_1;
+ int value_2;
};
+MyProceduralHitAttrs_0 MyProceduralHitAttrs_x24init_0(int value_3)
+{
+ MyProceduralHitAttrs_0 _S3;
+ _S3.value_2 = value_3;
+ return _S3;
+}
+
+bool myProceduralIntersection_0(inout float tHit_0, inout MyProceduralHitAttrs_0 hitAttrs_0)
+{
+ return true;
+}
+
bool myProceduralAnyHit_0(inout MyRayPayload_0 payload_0)
{
return true;
@@ -50,61 +78,59 @@ bool myTriangleAnyHit_0(inout MyRayPayload_0 payload_1)
void myTriangleClosestHit_0(inout MyRayPayload_0 payload_2)
{
- payload_2.value_1 = int(1);
+ payload_2.value_0 = int(1);
return;
}
void myProceduralClosestHit_0(inout MyRayPayload_0 payload_3, MyProceduralHitAttrs_0 attrs_0)
{
- payload_3.value_1 = attrs_0.value_0;
+ payload_3.value_0 = attrs_0.value_2;
return;
}
void myMiss_0(inout MyRayPayload_0 payload_4)
{
- payload_4.value_1 = int(0);
+ payload_4.value_0 = int(0);
return;
}
[shader("compute")][numthreads(1, 1, 1)]
-void main(uint3 tid_0 : SV_DISPATCHTHREADID)
+void main(uint3 tid_0 : SV_DispatchThreadID)
{
uint index_0 = tid_0.x;
- MyRayPayload_0 payload_5;
- payload_5.value_1 = int(-1);
- RayDesc ray_0 = { C_0.origin_0, C_0.tMin_0, C_0.direction_0, C_0.tMax_0 };
+ MyRayPayload_0 payload_5 = MyRayPayload_x24init_0(int(-1));
RayQuery<512U > query_0;
- query_0.TraceRayInline(myAccelerationStructure_0, C_0.rayFlags_0, C_0.instanceMask_0, ray_0);
+ query_0.TraceRayInline(myAccelerationStructure_0, C_0.rayFlags_0, C_0.instanceMask_0, RayDesc_x24init_0(C_0.origin_0, C_0.tMin_0, C_0.direction_0, C_0.tMax_0));
MyProceduralHitAttrs_0 committedProceduralAttrs_0;
+ MyProceduralHitAttrs_0 _S4 = MyProceduralHitAttrs_x24init_0(int(0));
for(;;)
{
- bool _S1 = query_0.Proceed();
- if(!_S1)
+ bool _S5 = query_0.Proceed();
+ if(!_S5)
{
break;
}
- uint _S2 = query_0.CandidateType();
+ uint _S6 = query_0.CandidateType();
MyProceduralHitAttrs_0 committedProceduralAttrs_1;
- switch(_S2)
+ switch(_S6)
{
case 1U:
{
- MyProceduralHitAttrs_0 candidateProceduralAttrs_0;
- candidateProceduralAttrs_0.value_0 = int(0);
+ MyProceduralHitAttrs_0 candidateProceduralAttrs_0 = _S4;
float tHit_1 = 0.0;
- bool _S3 = myProceduralIntersection_0(tHit_1, candidateProceduralAttrs_0);
- if(_S3)
+ bool _S7 = myProceduralIntersection_0(tHit_1, candidateProceduralAttrs_0);
+ if(_S7)
{
- bool _S4 = myProceduralAnyHit_0(payload_5);
- if(_S4)
+ bool _S8 = myProceduralAnyHit_0(payload_5);
+ if(_S8)
{
query_0.CommitProceduralPrimitiveHit(tHit_1);
- MyProceduralHitAttrs_0 _S5 = candidateProceduralAttrs_0;
- if(C_0.shouldStopAtFirstHit_0 != 0U)
+ MyProceduralHitAttrs_0 _S9 = candidateProceduralAttrs_0;
+ if((C_0.shouldStopAtFirstHit_0) != 0U)
{
query_0.Abort();
}
- committedProceduralAttrs_1 = _S5;
+ committedProceduralAttrs_1 = _S9;
}
else
{
@@ -119,11 +145,11 @@ void main(uint3 tid_0 : SV_DISPATCHTHREADID)
}
case 0U:
{
- bool _S6 = myTriangleAnyHit_0(payload_5);
- if(_S6)
+ bool _S10 = myTriangleAnyHit_0(payload_5);
+ if(_S10)
{
query_0.CommitNonOpaqueTriangleHit();
- if(C_0.shouldStopAtFirstHit_0 != 0U)
+ if((C_0.shouldStopAtFirstHit_0) != 0U)
{
query_0.Abort();
}
@@ -139,8 +165,8 @@ void main(uint3 tid_0 : SV_DISPATCHTHREADID)
}
committedProceduralAttrs_0 = committedProceduralAttrs_1;
}
- uint _S7 = query_0.CommittedStatus();
- switch(_S7)
+ uint _S11 = query_0.CommittedStatus();
+ switch(_S11)
{
case 1U:
{
@@ -162,6 +188,7 @@ void main(uint3 tid_0 : SV_DISPATCHTHREADID)
break;
}
}
- resultBuffer_0[index_0] = payload_5.value_1;
+ resultBuffer_0[index_0] = payload_5.value_0;
return;
}
+
diff --git a/tests/spirv/debug-type-pointer.slang b/tests/spirv/debug-type-pointer.slang
index 62bd4fda1..d6e8019cb 100644
--- a/tests/spirv/debug-type-pointer.slang
+++ b/tests/spirv/debug-type-pointer.slang
@@ -1,5 +1,5 @@
//TEST(compute, vulkan):SIMPLE(filecheck=SPV): -stage compute -entry computeMain -target spirv -emit-spirv-directly -g2
-//TEST(compute, vulkan):SIMPLE(filecheck=SPV): -stage compute -entry computeMain -target spirv -emit-spirv-directly -g2 -zero-initialize
+//DISABLE_TEST(compute, vulkan):SIMPLE(filecheck=SPV): -stage compute -entry computeMain -target spirv -emit-spirv-directly -g2 -zero-initialize
// This test is to check if DebugTypePointer is emitted when "-g2" option is used
diff --git a/tools/gfx/gfx.slang b/tools/gfx/gfx.slang
index e14f5e282..fded20eeb 100644
--- a/tools/gfx/gfx.slang
+++ b/tools/gfx/gfx.slang
@@ -105,9 +105,9 @@ public enum class ShaderModuleSourceType
public struct ShaderProgramDesc2
{
- public ShaderModuleSourceType sourceType;
- public void *sourceData;
- public Size sourceDataSize;
+ public ShaderModuleSourceType sourceType = ShaderModuleSourceType::SlangSource;
+ public void *sourceData = nullptr;
+ public Size sourceDataSize = 0;
// Number of entry points to include in the shader program. 0 means include all entry points
// defined in the module.
@@ -345,7 +345,7 @@ public enum class InteropHandleAPI
public struct InteropHandle
{
public InteropHandleAPI api = InteropHandleAPI::Unknown;
- public uint64_t handleValue;
+ public uint64_t handleValue = 0LLU;
};
// Declare opaque type
@@ -378,12 +378,12 @@ public enum class ResourceType
/// Base class for Descs
public struct ResourceDescBase
{
- public ResourceType type;
- public ResourceState defaultState;
- public ResourceStateSet allowedStates;
- public MemoryType memoryType;
- public InteropHandle existingHandle;
- public bool isShared;
+ public ResourceType type = ResourceType::Unknown;
+ public ResourceState defaultState = ResourceState::Undefined;
+ public ResourceStateSet allowedStates = {};
+ public MemoryType memoryType = MemoryType::DeviceLocal;
+ public InteropHandle existingHandle = {};
+ public bool isShared = false;
};
[COM("a0e39f34-8398-4522-95c2-ebc0f984ef3f")]
@@ -1056,6 +1056,7 @@ public struct AspectBlendDesc
{
srcFactor = BlendFactor::One;
dstFactor = BlendFactor::Zero;
+ op = BlendOp::Add;
}
};
@@ -1076,10 +1077,10 @@ public struct TargetBlendDesc
public struct BlendDesc
{
- public TargetBlendDesc targets[kMaxRenderTargetCount];
- public GfxCount targetCount;
+ public TargetBlendDesc targets[kMaxRenderTargetCount] = {};
+ public GfxCount targetCount = 0;
- public bool alphaToCoverageEnable;
+ public bool alphaToCoverageEnable = false;
};
public struct FramebufferTargetLayout
@@ -1113,7 +1114,13 @@ public struct GraphicsPipelineStateDesc
public __init()
{
+ program = {IShaderProgram()};
+ inputLayout = {IInputLayout()};
+ framebufferLayout = {IFramebufferLayout()};
primitiveType = PrimitiveType::Triangle;
+ depthStencil = {};
+ rasterizer = {};
+ blend = {};
}
};
@@ -1230,14 +1237,14 @@ public struct WindowHandle
public void* handleValues[2];
public static WindowHandle fromHwnd(void *hwnd)
{
- WindowHandle handle = {};
+ WindowHandle handle = {WindowHandleType::Unknown, {nullptr, nullptr}};
handle.type = WindowHandleType::Win32Handle;
handle.handleValues[0] = hwnd;
return handle;
}
public static WindowHandle fromXWindow(void *xdisplay, uint32_t xwindow)
{
- WindowHandle handle = {};
+ WindowHandle handle = {WindowHandleType::Unknown, {nullptr, nullptr}};
handle.type = WindowHandleType::XLibHandle;
handle.handleValues[0] = xdisplay;
handle.handleValues[1] = (void*)xwindow;
@@ -1698,17 +1705,17 @@ public interface IDebugCallback
public struct SlangDesc
{
- public NativeRef<slang::IGlobalSession> slangGlobalSession; // (optional) A slang global session object. If null will create automatically.
+ public NativeRef<slang::IGlobalSession> slangGlobalSession = {slang::IGlobalSession()}; // (optional) A slang global session object. If null will create automatically.
public slang::SlangMatrixLayoutMode defaultMatrixLayoutMode = slang::SlangMatrixLayoutMode::SLANG_MATRIX_LAYOUT_ROW_MAJOR;
- public NativeString *searchPaths;
- public GfxCount searchPathCount;
+ public NativeString *searchPaths = nullptr;
+ public GfxCount searchPathCount = 0;
- public slang::PreprocessorMacroDesc *preprocessorMacros;
+ public slang::PreprocessorMacroDesc *preprocessorMacros = nullptr;
public GfxCount preprocessorMacroCount = 0;
- public NativeString targetProfile; // (optional) Target shader profile. If null this will be set to platform dependent default.
+ public NativeString targetProfile = ""; // (optional) Target shader profile. If null this will be set to platform dependent default.
public slang::SlangFloatingPointMode floatingPointMode = slang::SlangFloatingPointMode::SLANG_FLOATING_POINT_MODE_DEFAULT;
public slang::SlangOptimizationLevel optimizationLevel = slang::SlangOptimizationLevel::SLANG_OPTIMIZATION_LEVEL_DEFAULT;
public slang::SlangTargetFlags targetFlags = slang::SlangTargetFlags.None;
@@ -1718,7 +1725,7 @@ public struct SlangDesc
public struct ShaderCacheDesc
{
// The root directory for the shader cache. If not set, shader cache is disabled.
- public NativeString shaderCachePath;
+ public NativeString shaderCachePath = "";
// The maximum number of entries stored in the cache.
public GfxCount maxEntryCount = 0;
};
@@ -1735,9 +1742,9 @@ public struct DeviceDesc
// The device's handles (if they exist) and their associated API. For D3D12, this contains a single InteropHandle
// for the ID3D12Device. For Vulkan, the first InteropHandle is the VkInstance, the second is the VkPhysicalDevice,
// and the third is the VkDevice. For CUDA, this only contains a single value for the CUDADevice.
- public DeviceInteropHandles existingDeviceHandles;
+ public DeviceInteropHandles existingDeviceHandles = {};
// Name to identify the adapter to use
- public NativeString adapter;
+ public NativeString adapter = "";
// Number of required features.
public GfxCount requiredFeatureCount = 0;
// Array of required feature names, whose size is `requiredFeatureCount`.
diff --git a/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp b/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp
index 512be9be5..0d6a333f0 100644
--- a/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp
+++ b/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp
@@ -130,10 +130,10 @@ SLANG_UNIT_TEST(declTreeReflection)
SLANG_CHECK(moduleDeclReflection->getKind() == slang::DeclReflection::Kind::Module);
SLANG_CHECK(moduleDeclReflection->getChildrenCount() == 9);
- // First declaration should be a struct with 1 variable
+ // First declaration should be a struct with 1 variable and a synthesized constructor
auto firstDecl = moduleDeclReflection->getChild(0);
SLANG_CHECK(firstDecl->getKind() == slang::DeclReflection::Kind::Struct);
- SLANG_CHECK(firstDecl->getChildrenCount() == 1);
+ SLANG_CHECK(firstDecl->getChildrenCount() == 2);
{
slang::TypeReflection* type = firstDecl->getType();