From 40f0cbe435706270471d47cecd83d3a06cf42ba3 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 6 Aug 2024 11:29:19 -0400 Subject: [PATCH 001/100] Member-wise constructor generation with visibility control NOTE: This is a draft Key Changes: 1. Initializer lists call into constructors (and no longer hack around per element) 2. we auto-generate member-wise constructors for varying visibility of members (public, public-internal, public-internal-private) 3. Implements visibility and member-wise constructor rules described in #3406 4. Reorders and reformats how we auto-generate constructors along with adding support for member-wise constructors ('visitStruct' and 'visitAggTypeDecl'). * This was changed since currently Slang (if no constructors are found) falls back to initializer list syntax for non initializer list constructor code. Since we add a non-default-ctor this fallback logic never happens causing failures now. 5. initialization-list logic for struct objects has been reordered and reformatted due to previous logical incompatibilities. --- source/slang/hlsl.meta.slang | 9 +- source/slang/slang-ast-decl.h | 22 +- source/slang/slang-check-conversion.cpp | 162 ++++-- source/slang/slang-check-decl.cpp | 514 +++++++++++++----- source/slang/slang-check-expr.cpp | 16 +- source/slang/slang-check-impl.h | 20 +- source/slang/slang-check-overload.cpp | 29 +- source/slang/slang-constructor-utility.cpp | 88 +++ source/slang/slang-diagnostic-defs.h | 2 +- source/slang/slang-lower-to-ir.cpp | 2 +- source/slang/slang.natvis | 1 + .../init-list-defaults.slang.expected.txt | 4 - .../initializer-list.slang.expected.txt | 4 - .../constructor-inheritance.slang | 168 ++++++ .../default-init-16bit-types.slang | 7 +- ...efault-init-16bit-types.slang.expected.txt | 4 - .../initializer-lists/defaults.slang} | 8 +- .../dont-synth-internal-constructor.slang | 41 ++ ...dont-synth-public-constructor-helper.slang | 23 + .../dont-synth-public-constructor.slang | 26 + ...-constructor-private-internal-helper.slang | 48 ++ .../synth-constructor-private-internal.slang | 27 + .../synth-constructor-private.slang | 62 +++ ...uctor-public-private-internal-helper.slang | 28 + ...-constructor-public-private-internal.slang | 24 + .../synth-constructor-public-private.slang | 50 ++ .../synth-constructor-public.slang | 31 ++ .../synth-constructor-visibility-error.slang | 37 ++ .../synth-constructor.slang} | 10 +- .../user-constructor-visibility-error.slang | 45 ++ .../initializer-lists/user-constructor.slang | 75 +++ .../unit-test-decl-tree-reflection.cpp | 6 +- 32 files changed, 1401 insertions(+), 192 deletions(-) create mode 100644 source/slang/slang-constructor-utility.cpp delete mode 100644 tests/compute/init-list-defaults.slang.expected.txt delete mode 100644 tests/compute/initializer-list.slang.expected.txt create mode 100644 tests/language-feature/initializer-lists/constructor-inheritance.slang delete mode 100644 tests/language-feature/initializer-lists/default-init-16bit-types.slang.expected.txt rename tests/{compute/init-list-defaults.slang => language-feature/initializer-lists/defaults.slang} (78%) create mode 100644 tests/language-feature/initializer-lists/dont-synth-internal-constructor.slang create mode 100644 tests/language-feature/initializer-lists/dont-synth-public-constructor-helper.slang create mode 100644 tests/language-feature/initializer-lists/dont-synth-public-constructor.slang create mode 100644 tests/language-feature/initializer-lists/synth-constructor-private-internal-helper.slang create mode 100644 tests/language-feature/initializer-lists/synth-constructor-private-internal.slang create mode 100644 tests/language-feature/initializer-lists/synth-constructor-private.slang create mode 100644 tests/language-feature/initializer-lists/synth-constructor-public-private-internal-helper.slang create mode 100644 tests/language-feature/initializer-lists/synth-constructor-public-private-internal.slang create mode 100644 tests/language-feature/initializer-lists/synth-constructor-public-private.slang create mode 100644 tests/language-feature/initializer-lists/synth-constructor-public.slang create mode 100644 tests/language-feature/initializer-lists/synth-constructor-visibility-error.slang rename tests/{compute/initializer-list.slang => language-feature/initializer-lists/synth-constructor.slang} (62%) create mode 100644 tests/language-feature/initializer-lists/user-constructor-visibility-error.slang create mode 100644 tests/language-feature/initializer-lists/user-constructor.slang diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 9760f974a9..dafd704943 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -15470,7 +15470,7 @@ struct RayDesc __target_intrinsic(hlsl, TMin) __target_intrinsic(cuda, TMin) - float TMin; + float TMin; __target_intrinsic(hlsl, Direction) __target_intrinsic(cuda, Direction) @@ -15478,7 +15478,7 @@ struct RayDesc __target_intrinsic(hlsl, TMax) __target_intrinsic(cuda, TMax) - float TMax; + float TMax; }; // 10.1.3 - Ray Acceleration Structure @@ -19511,6 +19511,11 @@ struct TextureFootprint : __TextureFootprintData { bool _isSingleLevel; + __init(__TextureFootprintData data, bool _isSingleLevelIn) + { + _isSingleLevel = _isSingleLevelIn; + } + property isSingleLevel : bool { [__NoSideEffect] diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h index af03ffbcb5..1963942006 100644 --- a/source/slang/slang-ast-decl.h +++ b/source/slang/slang-ast-decl.h @@ -367,14 +367,30 @@ class FunctionDeclBase : public CallableDecl Stmt* body = nullptr; }; +enum class ConstructorTags : int +{ + None = 0, + + /// Indicates whether the declaration was synthesized by + /// Slang and not actually provided by the user + Synthesized = 1 << 0, + + /// Derived classes will call this ctor if they need a memberwise ctor for public members. + MemberwiseCtorForPublicVisibility = 1 << 1, + + /// Derived classes will call this ctor if they need a memberwise ctor for public and internal members. + /// This ctor may be equal to 'isMemberwiseCtorForPublicVisibility' + MemberwiseCtorForInternalVisibility = 1 << 2, +}; + // A constructor/initializer to create instances of a type 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; + int options = (int)ConstructorTags::None; + void addOption(ConstructorTags option) { options |= (int)option; } + bool containsOption(ConstructorTags option) { return options & (int)option; } }; // A subscript operation used to index instances of a type diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 111f4e465c..1d56054fe1 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -128,7 +128,7 @@ namespace Slang // for aggregate initialization. // auto firstInitExpr = fromInitializerListExpr->args[ioInitArgIndex]; - if(shouldUseInitializerDirectly(toType, firstInitExpr)) + if(canCoerce(toType, firstInitExpr->type, firstInitExpr) && (shouldUseInitializerDirectly(toType, firstInitExpr))) { ioInitArgIndex++; return _coerce( @@ -201,6 +201,18 @@ namespace Slang return baseStructDeclRef; } + GenericAppDeclRef* _getGenericAppDeclRefType(Type* argType) + { + auto argDeclRefType = as(argType); + if (argDeclRefType) + { + if (auto genericType = as(argDeclRefType->getDeclRefBase())) + return genericType; + } + + return nullptr; + } + bool SemanticsVisitor::_readAggregateValueFromInitializerList( Type* inToType, Expr** outToExpr, @@ -222,6 +234,13 @@ namespace Slang if(ioArgIndex < argCount) { auto arg = fromInitializerListExpr->args[ioArgIndex++]; + + if (!canCoerce(toType, arg->type, nullptr)) + { + *outToExpr = arg; + return true; + } + return _coerce( CoercionSite::Initializer, toType, @@ -424,52 +443,123 @@ namespace Slang else if(auto toDeclRefType = as(toType)) { auto toTypeDeclRef = toDeclRefType->getDeclRef(); + // Trying to initialize a `struct` type given an initializer list. if(auto toStructDeclRef = toTypeDeclRef.as()) { - // Trying to initialize a `struct` type given an initializer list. - // - // Before we iterate over the fields, we want to check if this struct - // inherits from another `struct` type. If so, we want to read - // an initializer for that base type first. - // - if (auto baseStructType = findBaseStructType(m_astBuilder, toStructDeclRef)) + auto toStructDecl = toStructDeclRef.getDecl(); + ensureDecl(toStructDecl, DeclCheckState::DefaultConstructorReadyForUse); + + // We will try to coerce the initializer list (in order) into a constructor. + List ctorList = _getCtorList(this->getASTBuilder(), this, toStructDecl, nullptr); + + // Easy case of default constructor + if (argCount == 0) { - Expr* coercedArg = nullptr; - bool argResult = _readValueFromInitializerList( - baseStructType, - outToExpr ? &coercedArg : nullptr, - fromInitializerListExpr, - ioArgIndex); + if (outToExpr) + *outToExpr = constructDefaultInitExprForVar(this, (TypeExp)toType); + return true; + } - // No point in trying further if any argument fails - if (!argResult) - return false; + // Non-default constructor case + List maybeArgList; + maybeArgList.reserve(argCount); + Index ioArgIndexMirror = ioArgIndex; + UInt ioArgIndexCandidate = 0; + for (auto& ctor : ctorList) + { + auto ctorParamCount = ctor->getParameters().getCount(); + + ioArgIndexCandidate = ioArgIndexMirror; + ioArgIndex = ctorParamCount; + + // Skip if too many params expected by ctor + if (ctorParamCount != Index(argCount)) + continue; + + List maybeCandidate; + auto parameters = getParameters(m_astBuilder, ctor); + auto parametersCount = parameters.getCount(); + for (auto index = coercedArgs.getCount(); index < parametersCount; index++) + { + auto ctorParam = parameters[index]; + auto paramType = getType(getASTBuilder(), ctorParam); + + Expr* coercedArg = nullptr; + _readValueFromInitializerList( + paramType, + outToExpr ? &coercedArg : nullptr, + fromInitializerListExpr, + ioArgIndexCandidate); + + if (coercedArg) + maybeArgList.add(coercedArg); + else + break; + } - if (coercedArg) + if (maybeArgList.getCount() != ctor->getParameters().getCount()) + continue; + + // Skip non-visible constructors. + if (!isDeclVisible(ctor)) { - coercedArgs.add(coercedArg); + getSink()->diagnose(fromInitializerListExpr, Diagnostics::declIsNotVisible, ctor); + continue; + } + + // We cannot fail anymore, set ioArgIndex to the 'used up arg count'. + if (outToExpr) + { + ioArgIndex = ioArgIndexCandidate; + + for (auto i : maybeArgList) + coercedArgs.add(i); + + // We want lookup to resolve our init function as a generic using Slang's + // builtin 'lookup' logic. + auto ctorToInvoke = m_astBuilder->create(); + ctorToInvoke->scope = this->getOuterScope(); + ctorToInvoke->name = getName(String(toStructDecl->getName()->text)); + + Expr* callee = ctorToInvoke; + + InvokeExpr* constructorExpr = m_astBuilder->create(); + constructorExpr->loc = fromInitializerListExpr->loc; + constructorExpr->functionExpr = callee; + constructorExpr->arguments.addRange(coercedArgs); + constructorExpr->type = toType; + + *outToExpr = CheckExpr(constructorExpr); + + return true; } } - // We will go through the fields in order and try to match them - // up with initializer arguments. + // If we have a generic being compared to another generic (with different generic arguments) + // coerce logic will fail regardless of if generics are valid together. Example is below: // - for(auto fieldDeclRef : getMembersOfType(m_astBuilder, toStructDeclRef, MemberFilterStyle::Instance)) + // MyStruct tmp = {MyStructBase(), 1}; // assume 'U' is unresolved at this point in time but equal to T + // + // + // To handle this since this is not verifiable coerce logic: + // 1. We need to ensure we don't have any matching constructors + // 2. if '1.' is true we can assign the possibly compatible generics and let generic resolution diagnose + // if something makes zero sense. + if (auto toGenericType = _getGenericAppDeclRefType(toType)) { - Expr* coercedArg = nullptr; - bool argResult = _readValueFromInitializerList( - getType(m_astBuilder, fieldDeclRef), - outToExpr ? &coercedArg : nullptr, - fromInitializerListExpr, - ioArgIndex); - - // No point in trying further if any argument fails - if(!argResult) - return false; - - if( coercedArg ) + auto arg = fromInitializerListExpr->args[ioArgIndexMirror]; + if (auto fromGenericType = _getGenericAppDeclRefType(getType(m_astBuilder, arg))) { - coercedArgs.add(coercedArg); + for (;;) + { + if (toGenericType->getBase() != fromGenericType->getBase()) + break; + + ioArgIndex = ioArgIndexMirror; + *outToExpr = arg; + ioArgIndex++; + return true; + } } } } @@ -533,7 +623,7 @@ namespace Slang { if( outToExpr ) { - getSink()->diagnose(fromInitializerListExpr, Diagnostics::tooManyInitializers, argIndex, argCount); + getSink()->diagnose(fromInitializerListExpr, Diagnostics::tooManyInitializers, argCount); } } diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 59d8ba8b38..70dcaa7b16 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1789,7 +1789,30 @@ namespace Slang checkVisibility(varDecl); } - static ConstructorDecl* _createCtor(SemanticsDeclVisitorBase* visitor, ASTBuilder* m_astBuilder, AggTypeDecl* decl) + void addVisibilityModifier(ASTBuilder* builder, Decl* decl, DeclVisibility vis) + { + switch (vis) + { + case DeclVisibility::Public: + addModifier(decl, builder->create()); + break; + case DeclVisibility::Internal: + addModifier(decl, builder->create()); + break; + case DeclVisibility::Private: + addModifier(decl, builder->create()); + break; + default: + break; + } + } + + static ConstructorDecl* _createCtor( + SemanticsDeclVisitorBase* visitor, + ASTBuilder* m_astBuilder, + AggTypeDecl* decl, + List&& argList, + DeclVisibility visibility) { auto ctor = m_astBuilder->create(); addModifier(ctor, m_astBuilder->create()); @@ -1813,61 +1836,28 @@ namespace Slang body->closingSourceLoc = ctor->closingSourceLoc; ctor->body = body; body->body = m_astBuilder->create(); - ctor->isSynthesized = true; - decl->addMember(ctor); - return ctor; - } + ctor->addOption(ConstructorTags::Synthesized); - static ConstructorDecl* _getDefaultCtor(StructDecl* structDecl) - { - for (auto ctor : structDecl->getMembersOfType()) - { - if (!ctor->body || ctor->members.getCount() != 0) - continue; - return ctor; - } - return nullptr; - } + // kIROp_TorchTensorType must only refer to its own type through Host functions + // TODO: figure-out how to pass CudaHost for when we have a nested TorchTensor. + if(auto intrinsicType = decl->findModifier()) + if(intrinsicType->irOp == kIROp_TorchTensorType) + addModifier(ctor, m_astBuilder->create()); - - static List _getCtorList(ASTBuilder* m_astBuilder, SemanticsVisitor* visitor, StructDecl* structDecl, ConstructorDecl** defaultCtorOut) - { - List ctorList; - - auto ctorLookupResult = lookUpMember( - m_astBuilder, - visitor, - visitor->getName("$init"), - DeclRefType::create(m_astBuilder, structDecl), - structDecl->ownedScope, - LookupMask::Function, - (LookupOptions)((Index)LookupOptions::IgnoreInheritance | (Index)LookupOptions::NoDeref)); - - if (!ctorLookupResult.isValid()) - return ctorList; - - auto lookupResultHandle = [&](LookupResultItem& item) - { - auto ctor = as(item.declRef.getDecl()); - if (!ctor || !ctor->body) - return; - ctorList.add(ctor); - if (ctor->members.getCount() != 0) - return; - *defaultCtorOut = ctor; - }; - if (ctorLookupResult.items.getCount() == 0) - { - lookupResultHandle(ctorLookupResult.item); - return ctorList; - } - - for (auto m : ctorLookupResult.items) + for (auto arg : argList) { - lookupResultHandle(m); + auto param = m_astBuilder->create(); + param->type = (TypeExp)arg; + param->parentDecl = ctor; + param->loc = ctor->loc; + ctor->members.add(param); } - return ctorList; + addVisibilityModifier(m_astBuilder, ctor, visibility); + addModifier(ctor, m_astBuilder->create()); + + decl->addMember(ctor); + return ctor; } void SemanticsDeclHeaderVisitor::visitStructDecl(StructDecl* structDecl) @@ -1919,35 +1909,6 @@ namespace Slang checkVisibility(classDecl); } - static Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, VarDeclBase* varDecl) - { - if (!varDecl->type || !varDecl->type.type) - return nullptr; - - ConstructorDecl* defaultCtor = nullptr; - auto declRefType = as(varDecl->type.type); - if (declRefType) - { - if (auto structDecl = as(declRefType->getDeclRef().getDecl())) - { - defaultCtor = _getDefaultCtor(structDecl); - } - } - - if (defaultCtor) - { - auto* invoke = visitor->getASTBuilder()->create(); - auto member = visitor->getASTBuilder()->getMemberDeclRef(declRefType->getDeclRef(), defaultCtor); - invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->loc, nullptr); - return invoke; - } - else - { - auto* defaultCall = visitor->getASTBuilder()->create(); - defaultCall->type = QualType(varDecl->type); - return defaultCall; - } - } void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl) { // if zero initialize is true, set everything to a default @@ -1956,7 +1917,7 @@ namespace Slang && as(varDecl) ) { - varDecl->initExpr = constructDefaultInitExprForVar(this, varDecl); + varDecl->initExpr = constructDefaultInitExprForVar(this, varDecl->type); } if (auto initExpr = varDecl->initExpr) @@ -2151,24 +2112,6 @@ namespace Slang } } - void addVisibilityModifier(ASTBuilder* builder, Decl* decl, DeclVisibility vis) - { - switch (vis) - { - case DeclVisibility::Public: - addModifier(decl, builder->create()); - break; - case DeclVisibility::Internal: - addModifier(decl, builder->create()); - break; - case DeclVisibility::Private: - addModifier(decl, builder->create()); - break; - default: - break; - } - } - bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness( ConformanceCheckingContext* context, DeclRef requirementDeclRef, @@ -7630,6 +7573,11 @@ namespace Slang return as(stmt->body); } + static bool _doesCtorExpectInitializerListUsage(ConstructorDecl* ctor) + { + return ctor->containsOption(ConstructorTags::Synthesized) && ctor->getParameters().getCount() != 0; + } + void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl) { if (aggTypeDecl->hasTag(TypeTag::Incomplete) && aggTypeDecl->hasModifier()) @@ -7645,7 +7593,14 @@ namespace Slang { StructDecl* parent = nullptr; ConstructorDecl* defaultCtor = nullptr; - List ctorList; + + struct CtorAndInsertOffset + { + ConstructorDecl* ctor; + Index insertOffset; + }; + + List ctorInfoList; DeclAndCtorInfo() { } @@ -7654,9 +7609,15 @@ namespace Slang if (getOnlyDefault) defaultCtor = _getDefaultCtor(parent); else - ctorList = _getCtorList(m_astBuilder, visitor, parent, &defaultCtor); + { + auto ctorList = _getCtorList(m_astBuilder, visitor, parent, &defaultCtor); + ctorInfoList.reserve(ctorList.getCount()); + for(auto i : ctorList) + ctorInfoList.add({i, 0}); + } } }; + List inheritanceDefaultCtorList{}; for (auto inheritanceMember : structDecl->getMembersOfType()) { @@ -7682,14 +7643,22 @@ namespace Slang if (!isDefaultInitializableType || varDeclBase->initExpr) continue; - varDeclBase->initExpr = constructDefaultInitExprForVar(this, varDeclBase); + varDeclBase->initExpr = constructDefaultInitExprForVar(this, varDeclBase->type); } - Index insertOffset = 0; Dictionary cachedDeclToCheckedVar; - for (auto ctor : structDeclInfo.ctorList) + + // Insert 'this->base->__init()' into 'this->__init()'. + for (auto& ctorInfo : structDeclInfo.ctorInfoList) { - auto seqStmt = _ensureCtorBodyIsSeqStmt(m_astBuilder, ctor); + auto ctor = ctorInfo.ctor; + + // Synthesized constructors should not inject a defaultCtor of base-struct-type + // unless ctor has 0 parameters. This is to allow a ctor which desires to be + // init-list initialized to control which members initialize. + if(_doesCtorExpectInitializerListUsage(ctor)) + continue; + auto seqStmtChild = m_astBuilder->create(); seqStmtChild->stmts.reserve(inheritanceDefaultCtorList.getCount()); for (auto& declInfo : inheritanceDefaultCtorList) @@ -7710,6 +7679,11 @@ namespace Slang thisExpr->scope = ctor->ownedScope; thisExpr->type = ctor->returnType.type; + // A base may not have any value, if this is the case do not insert a `__init()` + // since coercing is impossible. + if (!canCoerce(declInfo.defaultCtor->returnType.type, ctor->returnType.type, thisExpr)) + continue; + auto assign = m_astBuilder->create(); assign->left = coerce(CoercionSite::Initializer, declInfo.defaultCtor->returnType.type, thisExpr); assign->right = invoke; @@ -7723,17 +7697,18 @@ namespace Slang if (seqStmtChild->stmts.getCount() == 0) continue; - seqStmt->stmts.insert(0, seqStmtChild); - insertOffset = 1; + auto seqStmt = _ensureCtorBodyIsSeqStmt(m_astBuilder, ctor); + seqStmt->stmts.insert(ctorInfo.insertOffset++, seqStmtChild); } - for (auto ctor : structDeclInfo.ctorList) + // Assign member variable init expressions + for (auto& ctorInfo : structDeclInfo.ctorInfoList) { + auto ctor = ctorInfo.ctor; ThisExpr* thisExpr = m_astBuilder->create(); thisExpr->scope = ctor->ownedScope; thisExpr->type = ctor->returnType.type; - auto seqStmt = _ensureCtorBodyIsSeqStmt(m_astBuilder, ctor); auto seqStmtChild = m_astBuilder->create(); seqStmtChild->stmts.reserve(structDecl->members.getCount()); for (auto& m : structDecl->members) @@ -7742,10 +7717,22 @@ namespace Slang // Static variables are initialized at start of runtime, not inside a constructor if (!varDeclBase - || !varDeclBase->initExpr || varDeclBase->hasModifier()) continue; + // Default initializer initializes/zero's out all values, + // do this here. + auto intendedInitExpr = varDeclBase->initExpr; + if(structDeclInfo.defaultCtor == ctor && !intendedInitExpr) + { + auto defaultExpr = m_astBuilder->create(); + defaultExpr->type = varDeclBase->type.type; + intendedInitExpr = defaultExpr; + } + + if (!intendedInitExpr) + continue; + MemberExpr* memberExpr = m_astBuilder->create(); memberExpr->baseExpression = thisExpr; memberExpr->declRef = m->getDefaultDeclRef(); @@ -7756,7 +7743,7 @@ namespace Slang auto assign = m_astBuilder->create(); assign->left = memberExpr; - assign->right = varDeclBase->initExpr; + assign->right = intendedInitExpr; assign->loc = m->loc; auto stmt = m_astBuilder->create(); @@ -7778,18 +7765,137 @@ namespace Slang } if (seqStmtChild->stmts.getCount() == 0) continue; - seqStmt->stmts.insert(insertOffset, seqStmtChild); + + auto seqStmt = _ensureCtorBodyIsSeqStmt(m_astBuilder, ctor); + seqStmt->stmts.insert(ctorInfo.insertOffset++, seqStmtChild); + } + + // Pre-calculate if we have a base-type and its associated ctor-list + auto baseStructRef = findBaseStructDeclRef(m_astBuilder, structDecl); + List baseTypeCtorList; + if (baseStructRef) + { + baseTypeCtorList = _getCtorList(m_astBuilder, this, baseStructRef.getDecl(), nullptr); } - if (structDeclInfo.defaultCtor) + // Insert parameters as values for member-wise init expression. + for (auto& ctorInfo : structDeclInfo.ctorInfoList) { - auto seqStmt = as(as(structDeclInfo.defaultCtor->body)->body); - if (seqStmt && seqStmt->stmts.getCount() == 0) + auto ctor = ctorInfo.ctor; + if(!_doesCtorExpectInitializerListUsage(ctor)) + continue; + auto ctorVisibility = getDeclVisibility(ctor); + + Index paramIndex = 0; + auto paramList = ctor->getParameters(); + + Index memberIndex = 0; + auto members = structDecl->getMembersOfType(); + + auto seqStmt = _ensureCtorBodyIsSeqStmt(m_astBuilder, ctor); + auto seqStmtChild = m_astBuilder->create(); + + ThisExpr* thisExpr = m_astBuilder->create(); + thisExpr->scope = ctor->ownedScope; + thisExpr->type = ctor->returnType.type; + + for (auto param : paramList) { - structDecl->members.remove(structDeclInfo.defaultCtor); - structDecl->invalidateMemberDictionary(); - structDecl->buildMemberDictionary(); + // If we have a base type, the first arg is a 'base->__init(...)'. We need to find this 'base->__init(...)' + // and assign the parameters needed to call '__init(...)' + if (paramIndex == 0 && baseTypeCtorList.getCount() > 0) + { + auto baseStruct = baseStructRef.getDecl(); + + // First find a member-wise 'base->__init()' which maps to this current ctor being filled + ConstructorDecl* baseCtor = nullptr; + ConstructorTags memberwiseCtorToCall = ConstructorTags::MemberwiseCtorForPublicVisibility; + if (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) + memberwiseCtorToCall = ConstructorTags::MemberwiseCtorForInternalVisibility; + for (auto i : baseTypeCtorList) + { + if (i->containsOption(memberwiseCtorToCall)) + { + baseCtor = i; + break; + } + } + if (baseCtor) + { + auto baseCtorParamCount = baseCtor->getParameters().getCount(); + + // Now assign the found ctor and add it to our auto-synthisized ctor + auto ctorToInvokeExpr = m_astBuilder->create(); + ctorToInvokeExpr->declRef = baseCtor->getDefaultDeclRef(); + ctorToInvokeExpr->name = baseCtor->getName(); + ctorToInvokeExpr->loc = baseCtor->loc; + ctorToInvokeExpr->type = baseCtor->returnType.type; + + auto invoke = m_astBuilder->create(); + invoke->functionExpr = ctorToInvokeExpr; + for (; paramIndex < baseCtorParamCount; paramIndex++) + { + auto paramToAdd = paramList[paramIndex]; + auto paramType = paramToAdd->getType(); + auto paramExpr = m_astBuilder->create(); + paramExpr->scope = ctor->ownedScope; + paramExpr->declRef = paramToAdd; + paramExpr->type = paramType; + paramExpr->loc = paramToAdd->loc; + + invoke->arguments.add(paramExpr); + } + + auto assign = m_astBuilder->create(); + assign->left = coerce(CoercionSite::Initializer, baseCtor->returnType.type, thisExpr); + assign->right = invoke; + auto stmt = m_astBuilder->create(); + stmt->expression = assign; + stmt->loc = ctor->loc; + seqStmtChild->stmts.add(stmt); + + continue; + } + } + + // Regular assignment logic + paramIndex++; + auto paramType = param->getType(); + auto paramExpr = m_astBuilder->create(); + paramExpr->scope = ctor->ownedScope; + paramExpr->declRef = param; + paramExpr->type = paramType; + paramExpr->loc = param->loc; + + // skip static members + VarDeclBase* member = members[memberIndex++]; + while (member->hasModifier() || getDeclVisibility(member) < ctorVisibility) + { + // Should note be possible to be out of range unless compiler generated a synth-ctor wrong. + SLANG_ASSERT(memberIndex < members.getCount()); + member = members[memberIndex++]; + } + + MemberExpr* memberExpr = m_astBuilder->create(); + 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()); + + auto assign = m_astBuilder->create(); + assign->left = memberExpr; + assign->right = paramExpr; + assign->loc = paramExpr->loc; + + auto stmt = m_astBuilder->create(); + stmt->expression = assign; + stmt->loc = assign->loc; + + seqStmtChild->stmts.add(stmt); } + seqStmt->stmts.insert(ctorInfo.insertOffset++, seqStmtChild); } } @@ -9986,13 +10092,177 @@ namespace Slang this, funcDecl, attr, DeclAssociationKind::PrimalSubstituteFunc); } + // Annotate ctor as a memberwise ctor. A non synthisized function may be annotated as a memberwise ctor + // if it has a compatible parameter list with a memberwise ctor. + void _annotateMemberwiseCtorWithVisibility(ConstructorDecl* ctor, DeclVisibility visibility) + { + switch (visibility) + { + case DeclVisibility::Public: + ctor->addOption(ConstructorTags::MemberwiseCtorForPublicVisibility); + break; + case DeclVisibility::Internal: + ctor->addOption(ConstructorTags::MemberwiseCtorForInternalVisibility); + break; + default: + break; + } + } + + static ConstructorDecl* _tryToGenerateCtorWithArgList( + SemanticsDeclVisitorBase* visitor, + ASTBuilder* astBuilder, + List&& args, + List& existingCtorList, + StructDecl* structDecl, + DeclVisibility visibility) + { + // Find any existing ctor type conflicts + for(auto ctor : existingCtorList) + { + auto existingCtorArgs = ctor->getParameters(); + auto existingCtorArgsLength = ctor->getParameters().getCount(); + auto newCtorArgsLength = args.getCount(); + + // Different arg count, ctor are not conflicting + if(existingCtorArgsLength != newCtorArgsLength) + continue; + + // if both arg lists are empty, return, we cannot have 2 default ctor's + if (!existingCtorArgsLength && !newCtorArgsLength) + return nullptr; + + // Check if every newCtorArg[i] is castable to existingCtorArg[i] (if so this is a conflicting ctor) + bool equalCtor = true; + for(Index i = 0; i < newCtorArgsLength; i++) + { + auto newCtorArg = args[i]; + auto existingCtorArg = existingCtorArgs[i]; + if (visitor->getConversionCost(newCtorArg, existingCtorArg->getType()) == kConversionCost_Impossible) + { + equalCtor = false; + break; + } + } + if (equalCtor) + { + _annotateMemberwiseCtorWithVisibility(ctor, visibility); + return nullptr; + } + } + + // We did not have any ctor conflicts, auto-generate a ctor + auto generatedCtor = _createCtor(visitor, astBuilder, structDecl, std::move(args), visibility); + existingCtorList.add(generatedCtor); + _annotateMemberwiseCtorWithVisibility(generatedCtor, visibility); + return generatedCtor; + } + void SemanticsDeclAttributesVisitor::visitStructDecl(StructDecl* structDecl) { - // add a empty deault CTor if missing; checking in attributes - // to avoid circular checking logic - auto defaultCtor = _getDefaultCtor(structDecl); + // Add an empty default Ctor if missing + ConstructorDecl* defaultCtor = nullptr; + List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); if (!defaultCtor) - _createCtor(this, m_astBuilder, structDecl); + { + defaultCtor = _createCtor(this, m_astBuilder, structDecl, {}, getDeclVisibility(structDecl)); + ctorList.add(defaultCtor); + } + + // Add an empty constructor for all combinations of visibility and access + // which is possible: + // 1. public constructor - usable *outside class scope* in a *different module* + List publicCtorArgs; + // 2. public-internal constructor - usable *outside class scope* in the *same module* + List publicInternalCtorArgs; + // 3. public-private-internal constructor - usable *inside class scope* in the *same module* + List publicPrivateInternalCtorArgs; + + // Harvest parameters which map to the base type ctor. + if(auto baseStructRef = findBaseStructDeclRef(m_astBuilder, structDecl)) + { + auto baseStruct = baseStructRef.getDecl(); + DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct,DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; + + ConstructorDecl* ctorForPublic = nullptr; + ConstructorDecl* ctorForInternal = nullptr; + + // From our synthisized ctor's find the publicMemberCtor and internalMemberCtor. + List baseCtorList = _getCtorList(this->getASTBuilder(), this, baseStruct, nullptr); + for (auto i : baseCtorList) + { + if (i->containsOption(ConstructorTags::MemberwiseCtorForPublicVisibility)) + ctorForPublic = i; + if (i->containsOption(ConstructorTags::MemberwiseCtorForInternalVisibility)) + ctorForInternal = i; + } + + // If base is not defined in the same module (or if the internal ctor is missing) + // set the parameter list to a base-type member-wise ctor. + if (baseVisibilityToDerived == DeclVisibility::Public + || !ctorForInternal) + { + ctorForInternal = ctorForPublic; + } + + if (ctorForPublic) + { + for (auto i : ctorForPublic->getParameters()) + { + publicCtorArgs.add(i->type); + } + for (auto i : ctorForInternal->getParameters()) + { + publicInternalCtorArgs.add(i->type); + publicPrivateInternalCtorArgs.add(i->type); + } + } + } + + // If we have a internal field which is not default-initialized we cannot allow + // a (1:1 element) ctor for public members (public member-wise ctor) to synthesize. + // This principal also applies for private members and internal/public member-wise ctor synthisis. + DeclVisibility maxVisibilityToGenerateCtor = getDeclVisibility(structDecl); + for(auto m : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) + { + if (auto varDeclRef = as(m)) + { + auto varDecl = varDeclRef.getDecl(); + ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); + auto declVisibility = getDeclVisibility(varDecl); + auto varDeclType = varDecl->type; + + switch (declVisibility) + { + case DeclVisibility::Private: + publicPrivateInternalCtorArgs.add(varDeclType); + if(!varDecl->initExpr) + maxVisibilityToGenerateCtor = DeclVisibility::Private; + break; + case DeclVisibility::Internal: + publicPrivateInternalCtorArgs.add(varDeclType); + publicInternalCtorArgs.add(varDeclType); + if (!varDecl->initExpr) + maxVisibilityToGenerateCtor = DeclVisibility::Internal; + break; + case DeclVisibility::Public: + publicPrivateInternalCtorArgs.add(varDeclType); + publicInternalCtorArgs.add(varDeclType); + publicCtorArgs.add(varDeclType); + break; + default: + // Unknown visibility + SLANG_ASSERT(false); + break; + } + } + } + if (maxVisibilityToGenerateCtor >= DeclVisibility::Public) + _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public); + if (maxVisibilityToGenerateCtor >= DeclVisibility::Internal) + _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal); + if (maxVisibilityToGenerateCtor >= DeclVisibility::Private) + _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicPrivateInternalCtorArgs), ctorList, structDecl, DeclVisibility::Private); int backingWidth = 0; [[maybe_unused]] diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index fd03e5e87c..eaff6c763b 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -880,9 +880,9 @@ namespace Slang return DeclVisibility::Public; } - bool SemanticsVisitor::isDeclVisibleFromScope(DeclRef declRef, Scope* scope) + + bool SemanticsVisitor::isVisibilityOfDeclVisibleInScope(DeclRef declRef, DeclVisibility visibility, Scope* scope) { - auto visibility = getDeclVisibility(declRef.getDecl()); if (visibility == DeclVisibility::Public) return true; if (visibility == DeclVisibility::Internal) @@ -911,7 +911,17 @@ namespace Slang } return false; } - return false; + return false; + } + + bool SemanticsVisitor::isDeclVisibleFromScope(DeclRef declRef, Scope* scope) + { + return isVisibilityOfDeclVisibleInScope(declRef, getDeclVisibility(declRef.getDecl()), scope); + } + + bool SemanticsVisitor::isDeclVisible(DeclRef declRef) + { + return isDeclVisibleFromScope(declRef, m_outerScope); } LookupResult SemanticsVisitor::filterLookupResultByVisibility(const LookupResult& lookupResult) diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 86655cedec..cc8e2d9092 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -1206,7 +1206,9 @@ namespace Slang Expr* originalExpr); DeclVisibility getTypeVisibility(Type* type); + bool isVisibilityOfDeclVisibleInScope(DeclRef declRef, DeclVisibility visibility, Scope* scope); bool isDeclVisibleFromScope(DeclRef declRef, Scope* scope); + bool isDeclVisible(DeclRef declRef); LookupResult filterLookupResultByVisibility(const LookupResult& lookupResult); LookupResult filterLookupResultByVisibilityAndDiagnose(const LookupResult& lookupResult, SourceLoc loc, bool& outDiagnosed); @@ -1449,7 +1451,7 @@ namespace Slang Type* toType, Expr** outToExpr, InitializerListExpr* fromInitializerListExpr, - UInt &ioInitArgIndex); + UInt &ioInitArgIndex); /// Read an aggregate value from an initializer list expression. /// @@ -2879,4 +2881,20 @@ namespace Slang FrontEndEntryPointRequest* entryPointReq); bool resolveStageOfProfileWithEntryPoint(Profile& entryPointProfile, CompilerOptionSet& optionSet, const List>& targets, FuncDecl* entryPointFuncDecl, DiagnosticSink* sink); + + LookupResult lookUpMember( + ASTBuilder* astBuilder, + SemanticsVisitor* semantics, + Name* name, + Type* type, + Scope* sourceScope, + LookupMask mask, + LookupOptions options); + + ConstructorDecl* _getDefaultCtor(StructDecl* structDecl); + List _getCtorList(ASTBuilder* m_astBuilder, SemanticsVisitor* visitor, StructDecl* structDecl, ConstructorDecl** defaultCtorOut); + Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, TypeExp varDeclType); + + DeclRefBase* _getDeclRefFromVal(Val* val); + } diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index d37c6e4698..419d902baf 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -1483,7 +1483,7 @@ namespace Slang ConstraintSystem constraints; constraints.loc = context.loc; constraints.genericDecl = genericDeclRef.getDecl(); - + auto innerDecl = genericDeclRef.getDecl()->inner; // In order to perform matching between the types passed in at the // call site represented by `context` and the parameters of the // declaraiton being applied, we want to form a reference to @@ -1493,7 +1493,32 @@ namespace Slang // Check what type of declaration we are dealing with, and then try // to match it up with the arguments accordingly... - if (auto funcDeclRef = as(genericDeclRef.getDecl()->inner)) + if (as(genericDeclRef.getDecl()->inner)) + { + // We have a ctor. We need to get the underlying callable. + auto functionVarExpr = as(context.originalExpr->functionExpr); + if (auto genericFunctionDeclRef = as(functionVarExpr->declRef)) + { + // Figure out what ctor we are using if our base is a struct decl + StructDecl* baseStruct = nullptr; + if (auto genericStructDecl = as(genericFunctionDeclRef.getDecl())) + baseStruct = as(genericStructDecl->inner); + if (baseStruct) + { + // TODO: search for valid ctor "more correctly" + auto ctorList = _getCtorList(getASTBuilder(), this, baseStruct, nullptr); + for (auto& i : ctorList) + { + if (i->getParameters().getCount() != context.argCount) + continue; + innerDecl = i; + break; + } + } + } + } + + if (auto funcDeclRef = as(innerDecl)) { List paramTypes; if (!innerParameterTypes) diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp new file mode 100644 index 0000000000..3af37b6854 --- /dev/null +++ b/source/slang/slang-constructor-utility.cpp @@ -0,0 +1,88 @@ +// slang-constructor-utility.cpp +#include "slang-check-impl.h" + +namespace Slang +{ + ConstructorDecl* _getDefaultCtor(StructDecl* structDecl) + { + for (auto ctor : structDecl->getMembersOfType()) + { + if (!ctor->body || ctor->members.getCount() != 0) + continue; + return ctor; + } + return nullptr; + } + + List _getCtorList(ASTBuilder* m_astBuilder, SemanticsVisitor* visitor, StructDecl* structDecl, ConstructorDecl** defaultCtorOut) + { + List ctorList; + + auto ctorLookupResult = lookUpMember( + m_astBuilder, + visitor, + visitor->getName("$init"), + DeclRefType::create(m_astBuilder, structDecl), + structDecl->ownedScope, + LookupMask::Function, + (LookupOptions)((Index)LookupOptions::IgnoreInheritance | (Index)LookupOptions::IgnoreBaseInterfaces | (Index)LookupOptions::NoDeref)); + + if (!ctorLookupResult.isValid()) + return ctorList; + + auto lookupResultHandle = [&](LookupResultItem& item) + { + auto ctor = as(item.declRef.getDecl()); + if (!ctor) + return; + ctorList.add(ctor); + if (ctor->members.getCount() != 0 || !defaultCtorOut) + return; + *defaultCtorOut = ctor; + }; + if (ctorLookupResult.items.getCount() == 0) + { + lookupResultHandle(ctorLookupResult.item); + return ctorList; + } + + for (auto m : ctorLookupResult.items) + { + lookupResultHandle(m); + } + + return ctorList; + } + + Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, TypeExp varDeclType) + { + if (!varDeclType || !varDeclType.type) + return nullptr; + + ConstructorDecl* defaultCtor = nullptr; + auto declRefType = as(varDeclType.type); + if (declRefType) + { + if (auto structDecl = as(declRefType->getDeclRef().getDecl())) + { + defaultCtor = _getDefaultCtor(structDecl); + } + } + + if (defaultCtor) + { + auto* invoke = visitor->getASTBuilder()->create(); + auto member = visitor->getASTBuilder()->getMemberDeclRef(declRefType->getDeclRef(), defaultCtor); + invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->loc, nullptr); + invoke->type = varDeclType.type; + return invoke; + } + else + { + auto* defaultCall = visitor->getASTBuilder()->create(); + defaultCall->type = QualType(varDeclType.type); + return defaultCall; + } + } +} + diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 78e37821d1..3146c29dbd 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -506,7 +506,7 @@ DIAGNOSTIC(30400, Error, genericTypeNeedsArgs, "generic type '$0' used without a DIAGNOSTIC(30401, Error, invalidTypeForConstraint, "type '$0' cannot be used as a constraint.") // 305xx: initializer lists -DIAGNOSTIC(30500, Error, tooManyInitializers, "too many initializers (expected $0, got $1)") +DIAGNOSTIC(30500, Error, tooManyInitializers, "cannot find matching constructor to call with arguments count of '$0'") DIAGNOSTIC(30501, Error, cannotUseInitializerListForArrayOfUnknownSize, "cannot use initializer list for array of statically unknown size '$0'") DIAGNOSTIC(30502, Error, cannotUseInitializerListForVectorOfUnknownSize, "cannot use initializer list for vector of statically unknown size '$0'") DIAGNOSTIC(30503, Error, cannotUseInitializerListForMatrixOfUnknownSize, "cannot use initializer list for matrix of statically unknown size '$0' rows") diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index d3770753c8..4d014bd42c 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -9694,7 +9694,7 @@ struct DeclLoweringVisitor : DeclVisitor } // Used for diagnostics - getBuilder()->addConstructorDecoration(irFunc, constructorDecl->isSynthesized); + getBuilder()->addConstructorDecoration(irFunc, constructorDecl->containsOption(ConstructorTags::Synthesized)); } // We lower whatever statement was stored on the declaration diff --git a/source/slang/slang.natvis b/source/slang/slang.natvis index 21db4016ff..94196c3729 100644 --- a/source/slang/slang.natvis +++ b/source/slang/slang.natvis @@ -278,6 +278,7 @@ (Slang::ContinueStmt*)&astNodeType (Slang::ReturnStmt*)&astNodeType (Slang::ExpressionStmt*)&astNodeType + (Slang::TargetSwitchStmt*)&astNodeType (Slang::Stmt*)this,! diff --git a/tests/compute/init-list-defaults.slang.expected.txt b/tests/compute/init-list-defaults.slang.expected.txt deleted file mode 100644 index fa9fe4c8a4..0000000000 --- a/tests/compute/init-list-defaults.slang.expected.txt +++ /dev/null @@ -1,4 +0,0 @@ -1142 -2453 -3060 -4000 diff --git a/tests/compute/initializer-list.slang.expected.txt b/tests/compute/initializer-list.slang.expected.txt deleted file mode 100644 index a0d427709c..0000000000 --- a/tests/compute/initializer-list.slang.expected.txt +++ /dev/null @@ -1,4 +0,0 @@ -10 -11 -12 -13 diff --git a/tests/language-feature/initializer-lists/constructor-inheritance.slang b/tests/language-feature/initializer-lists/constructor-inheritance.slang new file mode 100644 index 0000000000..90cb6bf4e5 --- /dev/null +++ b/tests/language-feature/initializer-lists/constructor-inheritance.slang @@ -0,0 +1,168 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF): -vk -compute -shaderobj + +// Test senario where we have constructors (partially defined through inheritance) +// and our init-list syntax calls into these constructors. + +public struct TestDerived1 +{ + private int val1 = 0; + public int val2 = 0; +} +public struct Test1 : TestDerived1 +{ + private int val3 = 0; + public int val4 = 0; +} + +public struct TestDerived2 +{ + private int val1 = 0; + public int val2 = 0; + + // This call overrides the memberwise constructor + // of the base type. + __init(int val) + { + this.val2 = val + 5; + } +} +public struct Test2 : TestDerived2 +{ + private int val3 = 0; + public int val4 = 0; + + // Does not override memberwise constructor + __init(int val) + { + val4 = val + 5; + } +} + +public struct TestDerived3 +{ + private int val1 = 0; + public int val2 = 0; + + // Does not get called since the derived type + // memberwise constructor is overloaded. + __init(int val) + { + this.val2 = val + 5; + } +} +public struct Test3 : TestDerived3 +{ + private int val3 = 0; + public int val4 = 0; + // This call overrides memberwise constructor, + // we ignore any inherited memberwise constructor. + __init(int val1, int val2) + { + this.val2 = val1 + 5; + this.val4 = val2 + 10; + } +} + +public struct TestDerived4 +{ + private int val1 = 0; + public int val2 = 0; +} +public struct Test4 : TestDerived4 +{ + private int val3 = 0; + public int val4 = 0; + __init(int val4, int val2) + { + this.val2 = val2 + 10; + this.val4 = val4; + } +} + +public struct TestDerived5 +{ + private int val1 = 0; + public int val2 = 0; +} +public struct Test5 : TestDerived5 +{ + private int val3 = 0; + public int val4 = 0; + + int getVal3() + { + return val3; + } + + static Test5 callPrivateMemberwiseCtor() + { + return { 1, 2, 3 }; + } +} + +public struct TestDerived6 +{ + private int val1 = 0; + public int val2 = 0; +} +public struct Test6 : TestDerived6 +{ + private int val3 = 0; + public int val4 = 0; + + __init(int val2, int val3, int val4) + { + this.val2 = val2*2; + this.val3 = val3*2; + this.val4 = val4*2; + } + + int getVal3() + { + return val3; + } + + static Test6 callPrivateMemberwiseCtor() + { + return { 1, 2, 3 }; + } +} + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test1 val1 = { 1, 2 }; + Test2 val2 = { 1, 2 }; + Test3 val3 = { 1, 2 }; + Test4 val4 = { 1, 2 }; + Test5 val5 = Test5::callPrivateMemberwiseCtor(); + Test6 val6 = Test6::callPrivateMemberwiseCtor(); + + outputBuffer[0] = (true + && val1.val2 == 1 + && val1.val4 == 2 + + && val2.val2 == 6 + && val2.val4 == 2 + + && val3.val2 == 6 + && val3.val4 == 12 + + && val4.val2 == 12 + && val4.val4 == 1 + + //&& val5.val2 == 1 + //&& val5.getVal3() == 2 + //&& val5.val4 == 3 + + //&& val5.val2 == 2 + //&& val5.getVal3() == 4 + //&& val5.val4 == 6 + + ) ? 1 : 0; + +// BUF: 1 +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/default-init-16bit-types.slang b/tests/language-feature/initializer-lists/default-init-16bit-types.slang index 9620534e25..c5d0518fa7 100644 --- a/tests/language-feature/initializer-lists/default-init-16bit-types.slang +++ b/tests/language-feature/initializer-lists/default-init-16bit-types.slang @@ -1,6 +1,6 @@ // simple-namespace.slang -//TEST(compute):COMPARE_COMPUTE:-vk -render-feature int16 +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -render-feature int16 // Test that default initialization works with 16-bit types under Vulkan. @@ -31,5 +31,10 @@ void computeMain(int3 dispatchThreadID : SV_DispatchThreadID) int tid = dispatchThreadID.x; int inVal = tid; int outVal = test(inVal); + +//BUF: 0 +//BUF: 1111 +//BUF: 2222 +//BUF: 3333 outputBuffer[tid] = outVal; } diff --git a/tests/language-feature/initializer-lists/default-init-16bit-types.slang.expected.txt b/tests/language-feature/initializer-lists/default-init-16bit-types.slang.expected.txt deleted file mode 100644 index 6dbd5c939b..0000000000 --- a/tests/language-feature/initializer-lists/default-init-16bit-types.slang.expected.txt +++ /dev/null @@ -1,4 +0,0 @@ -0 -1111 -2222 -3333 diff --git a/tests/compute/init-list-defaults.slang b/tests/language-feature/initializer-lists/defaults.slang similarity index 78% rename from tests/compute/init-list-defaults.slang rename to tests/language-feature/initializer-lists/defaults.slang index 0494501098..379ccb75d0 100644 --- a/tests/compute/init-list-defaults.slang +++ b/tests/language-feature/initializer-lists/defaults.slang @@ -1,6 +1,6 @@ // init-list-defaults.slang -//TEST(compute):COMPARE_COMPUTE: -shaderobj -//TEST(compute):COMPARE_COMPUTE:-cpu -shaderobj +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF):-cpu -shaderobj // Confirm that initializer lists correctly default-initialize elements past those specified. @@ -34,5 +34,9 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) int inVal = int(tid); int outVal = test(inVal); +//BUF: 1142 +//BUF: 2453 +//BUF: 3060 +//BUF: 4000 outputBuffer[tid] = outVal; } \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/dont-synth-internal-constructor.slang b/tests/language-feature/initializer-lists/dont-synth-internal-constructor.slang new file mode 100644 index 0000000000..4355b92f66 --- /dev/null +++ b/tests/language-feature/initializer-lists/dont-synth-internal-constructor.slang @@ -0,0 +1,41 @@ +//TEST:SIMPLE(filecheck=ERROR): -target spirv -entry computeMain -stage compute + +// Test senario where an 'private' member is not default-initialized +// for a struct but we call into a "internal" memberwise ctor. +// The called "internal" memberwise ctor should not be synth'ed. + +//ERROR: error 30500 +public struct TestNested +{ + public int val1; + public int val2; +} + +public struct Test +{ + private int val1; + public int val2; + public TestNested nested1; + + int getVal1() + { + return val1; + } +}; + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test val1 = { 1, { 2, 3 } }; + outputBuffer[0] = (true + && val1.getVal1() == 2 + && val1.val2 == 2 + && val1.nested1.val1 == 2 + && val1.nested1.val2 == 2 + ) ? 1 : 0; + +// BUF: 1 +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/dont-synth-public-constructor-helper.slang b/tests/language-feature/initializer-lists/dont-synth-public-constructor-helper.slang new file mode 100644 index 0000000000..8b128415c0 --- /dev/null +++ b/tests/language-feature/initializer-lists/dont-synth-public-constructor-helper.slang @@ -0,0 +1,23 @@ +// Have a seperate file to ensure we are not trying to call an 'internal' synth'ed constructor. + +public struct TestNested +{ + public int val1; + public int val2; +} + +public struct Test +{ +#ifdef TEST_INTERNAL + internal int val1; +#else + private int val1; +#endif + public int val2; + public TestNested nested1; + + public int getVal1() + { + return val1; + } +}; \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/dont-synth-public-constructor.slang b/tests/language-feature/initializer-lists/dont-synth-public-constructor.slang new file mode 100644 index 0000000000..800b20863f --- /dev/null +++ b/tests/language-feature/initializer-lists/dont-synth-public-constructor.slang @@ -0,0 +1,26 @@ +//TEST:SIMPLE(filecheck=ERROR): -target spirv -entry computeMain -stage compute -DTEST_INTERNAL +//TEST:SIMPLE(filecheck=ERROR): -target spirv -entry computeMain -stage compute + +// Test senario where a 'private'/'internal' member is not default-initialized +// for a struct but we call into a "public" memberwise ctor. +// The called "public" memberwise ctor should not be synth'ed. + +// ERROR: error 30500 +import dont_synth_public_constructor_helper; + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test val1 = { 1, { 2, 3 } }; + outputBuffer[0] = (true + && val1.getVal1() == 2 + && val1.val2 == 2 + && val1.nested1.val1 == 2 + && val1.nested1.val2 == 2 + ) ? 1 : 0; + +// BUF: 1 +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/synth-constructor-private-internal-helper.slang b/tests/language-feature/initializer-lists/synth-constructor-private-internal-helper.slang new file mode 100644 index 0000000000..876e180345 --- /dev/null +++ b/tests/language-feature/initializer-lists/synth-constructor-private-internal-helper.slang @@ -0,0 +1,48 @@ +public struct TestNested +{ + private int val1 = 0; + internal int val2; + + public int getVal1() + { + return val1; + } + public int getVal2() + { + return val2; + } +} + +public struct Test +{ + private int val1 = 0; + internal int val2; + private TestNested nested1 = { 0 }; + private TestNested nested2 = { 0 }; + + public static Test getTest() + { + return { 1, 2, { 3 }, { 4 }}; + } + public int getVal1() + { + return val1; + } + public int getVal2() + { + return val2; + } + public TestNested getNested1() + { + return nested1; + } + public TestNested getNested2() + { + return nested2; + } +}; + +public Test getTest() +{ + return { 1 }; +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/synth-constructor-private-internal.slang b/tests/language-feature/initializer-lists/synth-constructor-private-internal.slang new file mode 100644 index 0000000000..64c33b9811 --- /dev/null +++ b/tests/language-feature/initializer-lists/synth-constructor-private-internal.slang @@ -0,0 +1,27 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF): -vk -compute -shaderobj + +import synth_constructor_private_internal_helper; + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test val1 = getTest(); + Test val2 = Test::getTest(); + outputBuffer[0] = (true + && val1.getVal2() == 1 + && val1.getNested1().getVal1() == 0 + && val1.getNested1().getVal2() == 0 + && val1.getNested2().getVal1() == 0 + && val1.getNested2().getVal2() == 0 + + && val2.getVal1() == 1 + && val2.getVal2() == 2 + && val2.getNested1().getVal2() == 3 + && val2.getNested2().getVal2() == 4 + ) ? 1 : 0; + +// BUF: 1 +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/synth-constructor-private.slang b/tests/language-feature/initializer-lists/synth-constructor-private.slang new file mode 100644 index 0000000000..b28d394ec0 --- /dev/null +++ b/tests/language-feature/initializer-lists/synth-constructor-private.slang @@ -0,0 +1,62 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF): -vk -compute -shaderobj + +public struct TestNested +{ + private int val1; + private int val2; + + int getVal1() + { + return val1; + } + int getVal2() + { + return val2; + } +} + +public struct Test +{ + private int val1; + private int val2; + private TestNested nested1; + + static Test getTest() + { + return { 1, 2, {}}; + } + + int getVal1() + { + return val1; + } + int getVal2() + { + return val2; + } + TestNested getNested1() + { + return nested1; + } +}; + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test val1 = {}; + Test val2 = Test::getTest(); + outputBuffer[0] = (true + && val1.getVal1() == 0 + && val1.getNested1().getVal1() == 0 + + && val2.getVal1() == 1 + && val2.getVal2() == 2 + && val2.getNested1().getVal1() == 0 + && val2.getNested1().getVal2() == 0 + ) ? 1 : 0; + +// BUF: 1 +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/synth-constructor-public-private-internal-helper.slang b/tests/language-feature/initializer-lists/synth-constructor-public-private-internal-helper.slang new file mode 100644 index 0000000000..81c80a0db8 --- /dev/null +++ b/tests/language-feature/initializer-lists/synth-constructor-public-private-internal-helper.slang @@ -0,0 +1,28 @@ +public struct NestedTest +{ + internal int val1 = 0; + private int val2 = 0; + public int val3; + + public int getVal1() + { + return val1; + } +} +public struct Test +{ + internal int val1 = 0; + private int val2 = 0; + public int val3; + public NestedTest nested1 = { 0, 0 }; + + public int getVal1() + { + return val1; + } +} + +public Test makeInternal() +{ + return { 1, 2, { 3, 4 } }; +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/synth-constructor-public-private-internal.slang b/tests/language-feature/initializer-lists/synth-constructor-public-private-internal.slang new file mode 100644 index 0000000000..53355bd869 --- /dev/null +++ b/tests/language-feature/initializer-lists/synth-constructor-public-private-internal.slang @@ -0,0 +1,24 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF): -vk -compute -shaderobj + +import synth_constructor_public_private_internal_helper; + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test val1 = { 1, { 2 } }; + Test val2 = makeInternal(); + outputBuffer[0] = (true + && val1.val3 == 1 + && val1.nested1.val3 == 2 + + && val2.getVal1() == 1 + && val2.val3 == 2 + && val2.nested1.getVal1() == 3 + && val2.nested1.val3 == 4 + ) ? 1 : 0; + +// BUF: 1 +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/synth-constructor-public-private.slang b/tests/language-feature/initializer-lists/synth-constructor-public-private.slang new file mode 100644 index 0000000000..181ccffe94 --- /dev/null +++ b/tests/language-feature/initializer-lists/synth-constructor-public-private.slang @@ -0,0 +1,50 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF): -vk -compute -shaderobj + +public struct TestNested +{ + private int val1 = 0; + public int val2; +} + +public struct Test +{ + private int val1 = 0; + public int val2; + public TestNested nested1 = { 0 }; + private TestNested nested2 = { 0 }; + + static Test getTest() + { + return { 1, 2, { 3 }, { 4 } }; + } + + int getVal1() + { + return val1; + } + TestNested getNested2() + { + return nested2; + } +}; + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test val1 = { 1, { 2 } }; + Test val2 = Test::getTest(); + outputBuffer[0] = (true + && val1.val2 == 1 + && val1.nested1.val2 == 2 + + && val2.getVal1() == 1 + && val2.val2 == 2 + && val2.nested1.val2 == 3 + && val2.getNested2().val2 == 4 + ) ? 1 : 0; + +// BUF: 1 +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/synth-constructor-public.slang b/tests/language-feature/initializer-lists/synth-constructor-public.slang new file mode 100644 index 0000000000..83735403d9 --- /dev/null +++ b/tests/language-feature/initializer-lists/synth-constructor-public.slang @@ -0,0 +1,31 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF): -vk -compute -shaderobj + +public struct TestNested +{ + public int val1; + public int val2; +} + +public struct Test +{ + public int val1; + public int val2; + public TestNested nested1; +}; + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test val = { 1, 2, { 3, 4 } }; + outputBuffer[0] = (true + && val.val1 == 1 + && val.val2 == 2 + && val.nested1.val1 == 3 + && val.nested1.val2 == 4 + ) ? 1 : 0; + +// BUF: 1 +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/synth-constructor-visibility-error.slang b/tests/language-feature/initializer-lists/synth-constructor-visibility-error.slang new file mode 100644 index 0000000000..6895c9f625 --- /dev/null +++ b/tests/language-feature/initializer-lists/synth-constructor-visibility-error.slang @@ -0,0 +1,37 @@ +//TEST:SIMPLE(filecheck=ERROR): -target spirv -entry computeMain -stage compute + +// Test senario where user calls into a synth'ed memberwise constructor +// of "private" visibility from an "internal" visible scope. + +//ERROR: error 30600 +public struct TestNested +{ + public int val1; + public int val2; +} + +public struct Test +{ + private int val1; + public int val2; + public TestNested nested1; + + int getVal1() + { + return val1; + } +}; + +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test val1 = { 2, 1, { 1, 1 } }; + outputBuffer[0] = (true + && val1.getVal1() == 2 + && val1.val2 == 2 + && val1.nested1.val1 == 2 + && val1.nested1.val2 == 2 + ) ? 1 : 0; +} \ No newline at end of file diff --git a/tests/compute/initializer-list.slang b/tests/language-feature/initializer-lists/synth-constructor.slang similarity index 62% rename from tests/compute/initializer-list.slang rename to tests/language-feature/initializer-lists/synth-constructor.slang index 85ad0d8cfb..ac683ae79f 100644 --- a/tests/compute/initializer-list.slang +++ b/tests/language-feature/initializer-lists/synth-constructor.slang @@ -1,5 +1,5 @@ -//TEST(compute):COMPARE_COMPUTE: -shaderobj -//TEST(compute):COMPARE_COMPUTE:-cpu -shaderobj +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF):-cpu -shaderobj struct Test { @@ -11,7 +11,7 @@ struct Test uint test(uint val) { - Test t = { float4(1.0f), 16, 99.0f }; + Test t = { { 1.0f, 1.0f, 1.0f, 1.0f }, 16, 99.0f }; return val + t.b; } @@ -26,5 +26,9 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) uint inVal = tid; uint outVal = test(inVal); +//BUF: 10 +//BUF-NEXT: 11 +//BUF-NEXT: 12 +//BUF-NEXT: 13 outputBuffer[tid] = outVal; } \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/user-constructor-visibility-error.slang b/tests/language-feature/initializer-lists/user-constructor-visibility-error.slang new file mode 100644 index 0000000000..802f03fb9e --- /dev/null +++ b/tests/language-feature/initializer-lists/user-constructor-visibility-error.slang @@ -0,0 +1,45 @@ +//TEST:SIMPLE(filecheck=ERROR): -target spirv -entry computeMain -stage compute + +// Test senario where user calls into a user defined constructor +// of "private" visibility from an "internal" visible scope. + +//ERROR: error 30600 +public struct TestNested +{ + public int val1; + public int val2; +} + +public struct Test +{ + private int val1; + public int val2; + public TestNested nested1; + + int getVal1() + { + return val1; + } + + private __init(int in1) + { + this.val1 = in1; + this.val2 = in1; + this.nested1.val1 = in1; + this.nested1.val2 = in1; + } +}; + +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test val1 = { 2 }; + outputBuffer[0] = (true + && val1.getVal1() == 2 + && val1.val2 == 2 + && val1.nested1.val1 == 2 + && val1.nested1.val2 == 2 + ) ? 1 : 0; +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/user-constructor.slang b/tests/language-feature/initializer-lists/user-constructor.slang new file mode 100644 index 0000000000..63c3def7ae --- /dev/null +++ b/tests/language-feature/initializer-lists/user-constructor.slang @@ -0,0 +1,75 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUF): -vk -compute -shaderobj + +// Test senario where user defines constructors +// and our init-list syntax calls into those constructors + +public struct TestNested +{ + public int val1; + public int val2; +} + +public struct Test +{ + private int val1; + public int val2; + public TestNested nested1; + + int getVal1() + { + return val1; + } + + __init(int in1, TestNested in2) + { + this.val1 = in1; + this.val2 = in1; + this.nested1 = in2; + this.nested1.val1 = in1; + } + + __init(int in1) + { + this.val1 = in1; + this.val2 = in1; + this.nested1.val1 = in1; + this.nested1.val2 = in1; + } + + __init() + { + this.val1 = 5; + this.val2 = 5; + this.nested1.val1 = 5; + this.nested1.val2 = 5; + } +}; + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test val1 = { 1, { 2, 3 } }; + Test val2 = { 2 }; + Test val3 = {}; + outputBuffer[0] = (true + && val1.getVal1() == 1 + && val1.val2 == 1 + && val1.nested1.val1 == 1 + && val1.nested1.val2 == 3 + + && val2.getVal1() == 2 + && val2.val2 == 2 + && val2.nested1.val1 == 2 + && val2.nested1.val2 == 2 + + && val3.getVal1() == 5 + && val3.val2 == 5 + && val3.nested1.val1 == 5 + && val3.nested1.val2 == 5 + ) ? 1 : 0; + +// BUF: 1 +} \ No newline at end of file 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 e443358fb3..d907ca07e5 100644 --- a/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp +++ b/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp @@ -80,16 +80,16 @@ SLANG_UNIT_TEST(declTreeReflection) SLANG_CHECK(moduleDeclReflection->getKind() == slang::DeclReflection::Kind::Module); SLANG_CHECK(moduleDeclReflection->getChildrenCount() == 4); - // First declaration should be a struct with 1 variable + // First declaration should be a struct with 1 variable and 2 constructor (memberwise and default ctor) auto firstDecl = moduleDeclReflection->getChild(0); SLANG_CHECK(firstDecl->getKind() == slang::DeclReflection::Kind::Struct); - SLANG_CHECK(firstDecl->getChildrenCount() == 1); + SLANG_CHECK(firstDecl->getChildrenCount() == 3); { slang::TypeReflection* type = firstDecl->getType(globalSession); SLANG_CHECK(getTypeFullName(type) == "MyFuncPropertyAttribute"); - // Check the field of the struct. + // Check the field of the struct SLANG_CHECK(type->getFieldCount() == 1); auto field = type->getFieldByIndex(0); SLANG_CHECK(UnownedStringSlice(field->getName()) == "v"); From ceb70c4a54e52e25b68658f7e9abc1d11b3cf983 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:47:22 -0400 Subject: [PATCH 002/100] fix bug which causes crash --- source/slang/slang-check-decl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 70dcaa7b16..ec8f410210 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7799,8 +7799,10 @@ namespace Slang thisExpr->scope = ctor->ownedScope; thisExpr->type = ctor->returnType.type; - for (auto param : paramList) + auto paramCount = paramList.getCount(); + while (paramIndex < paramCount) { + auto param = paramList[paramIndex]; // If we have a base type, the first arg is a 'base->__init(...)'. We need to find this 'base->__init(...)' // and assign the parameters needed to call '__init(...)' if (paramIndex == 0 && baseTypeCtorList.getCount() > 0) From 0110058c547845878d85ea89f8ace455257f0715 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:11:37 -0400 Subject: [PATCH 003/100] git merge fix --- source/slang/slang-check-conversion.cpp | 2 +- source/slang/slang-check-decl.cpp | 83 +--------------------- source/slang/slang-check-impl.h | 4 +- source/slang/slang-constructor-utility.cpp | 58 ++++++++++++++- 4 files changed, 63 insertions(+), 84 deletions(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index cbdda6c59e..580ab5d5df 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -456,7 +456,7 @@ namespace Slang if (argCount == 0) { if (outToExpr) - *outToExpr = constructDefaultInitExprForVar(this, (TypeExp)toType); + *outToExpr = constructDefaultInitExprForVar(this, (TypeExp)toType, nullptr); return true; } diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index c38ae6dde9..bdade0f560 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1912,85 +1912,6 @@ namespace Slang checkVisibility(classDecl); } - bool DiagnoseIsAllowedInitExpr(VarDeclBase* varDecl, DiagnosticSink* sink) - { - // find groupshared modifier - if (varDecl->findModifier()) - { - if (sink && varDecl->initExpr) - sink->diagnose(varDecl, Diagnostics::cannotHaveInitializer, varDecl, "groupshared"); - return false; - } - - return true; - } - - bool isDefaultInitializable(VarDeclBase* varDecl) - { - if (!DiagnoseIsAllowedInitExpr(varDecl, nullptr)) - return false; - - // Find struct and modifiers associated with varDecl - StructDecl* structDecl = as(varDecl); - if (auto declRefType = as(varDecl->getType())) - { - if (auto genericAppRefDecl = as(declRefType->getDeclRefBase())) - { - auto baseGenericRefType = genericAppRefDecl->getBase()->getDecl(); - if (auto baseTypeStruct = as(baseGenericRefType)) - { - structDecl = baseTypeStruct; - } - else if (auto genericDecl = as(baseGenericRefType)) - { - if(auto innerTypeStruct = as(genericDecl->inner)) - structDecl = innerTypeStruct; - } - } - } - if (structDecl) - { - // find if a type is non-copyable - if (structDecl->findModifier()) - return false; - } - - return true; - } - - static Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, VarDeclBase* varDecl) - { - if (!varDecl->type || !varDecl->type.type) - return nullptr; - - if (!isDefaultInitializable(varDecl)) - return nullptr; - - ConstructorDecl* defaultCtor = nullptr; - auto declRefType = as(varDecl->type.type); - if (declRefType) - { - if (auto structDecl = as(declRefType->getDeclRef().getDecl())) - { - defaultCtor = _getDefaultCtor(structDecl); - } - } - - if (defaultCtor) - { - auto* invoke = visitor->getASTBuilder()->create(); - auto member = visitor->getASTBuilder()->getMemberDeclRef(declRefType->getDeclRef(), defaultCtor); - invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->loc, nullptr); - return invoke; - } - else - { - auto* defaultCall = visitor->getASTBuilder()->create(); - defaultCall->type = QualType(varDecl->type); - return defaultCall; - } - } - void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl) { DiagnoseIsAllowedInitExpr(varDecl, getSink()); @@ -2001,7 +1922,7 @@ namespace Slang && as(varDecl) ) { - varDecl->initExpr = constructDefaultInitExprForVar(this, varDecl->type); + varDecl->initExpr = constructDefaultInitExprForVar(this, varDecl->type, varDecl); } if (auto initExpr = varDecl->initExpr) @@ -7826,7 +7747,7 @@ namespace Slang if (!isDefaultInitializableType || varDeclBase->initExpr) continue; - varDeclBase->initExpr = constructDefaultInitExprForVar(this, varDeclBase->type); + varDeclBase->initExpr = constructDefaultInitExprForVar(this, varDeclBase->type, varDeclBase); } Dictionary cachedDeclToCheckedVar; diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 1ac7bf5585..6d94a4ac84 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -2935,7 +2935,9 @@ namespace Slang ConstructorDecl* _getDefaultCtor(StructDecl* structDecl); List _getCtorList(ASTBuilder* m_astBuilder, SemanticsVisitor* visitor, StructDecl* structDecl, ConstructorDecl** defaultCtorOut); - Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, TypeExp varDeclType); + bool DiagnoseIsAllowedInitExpr(VarDeclBase* varDecl, DiagnosticSink* sink); + bool isDefaultInitializable(Type* varDeclType, VarDeclBase* associatedDecl); + Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, TypeExp varDeclType, VarDeclBase* decl); DeclRefBase* _getDeclRefFromVal(Val* val); diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index 3af37b6854..3e413c239b 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -54,11 +54,67 @@ namespace Slang return ctorList; } - Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, TypeExp varDeclType) + bool DiagnoseIsAllowedInitExpr(VarDeclBase* varDecl, DiagnosticSink* sink) + { + if (!varDecl) + return true; + + // find groupshared modifier + if (varDecl->findModifier()) + { + if (sink && varDecl->initExpr) + sink->diagnose(varDecl, Diagnostics::cannotHaveInitializer, varDecl, "groupshared"); + return false; + } + + return true; + } + + bool isDefaultInitializable(Type* varDeclType, VarDeclBase* associatedDecl) + { + if (!DiagnoseIsAllowedInitExpr(associatedDecl, nullptr)) + return false; + + // Find struct and modifiers associated with varDecl + StructDecl* structDecl = nullptr; + if (auto declRefType = as(varDeclType)) + { + if (auto genericAppRefDecl = as(declRefType->getDeclRefBase())) + { + auto baseGenericRefType = genericAppRefDecl->getBase()->getDecl(); + if (auto baseTypeStruct = as(baseGenericRefType)) + { + structDecl = baseTypeStruct; + } + else if (auto genericDecl = as(baseGenericRefType)) + { + if (auto innerTypeStruct = as(genericDecl->inner)) + structDecl = innerTypeStruct; + } + } + else + { + structDecl = as(declRefType->getDeclRef().getDecl()); + } + } + if (structDecl) + { + // find if a type is non-copyable + if (structDecl->findModifier()) + return false; + } + + return true; + } + + Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, TypeExp varDeclType, VarDeclBase* decl) { if (!varDeclType || !varDeclType.type) return nullptr; + if (!isDefaultInitializable(varDeclType.type, decl)) + return nullptr; + ConstructorDecl* defaultCtor = nullptr; auto declRefType = as(varDeclType.type); if (declRefType) From 0dca4952064595d828cfb637744e3aa10285d023 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:38:48 -0400 Subject: [PATCH 004/100] fix default init expr with init expr paramDecl --- source/slang/slang-constructor-utility.cpp | 10 ++++++-- ...ynth-constructor-conflicting-default.slang | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index 3e413c239b..1d8f5a42fe 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -13,7 +13,13 @@ namespace Slang } return nullptr; } - + bool allParamHaveInitExpr(ConstructorDecl* ctor) + { + for (auto i : ctor->getParameters()) + if (!i->initExpr) + return false; + return true; + } List _getCtorList(ASTBuilder* m_astBuilder, SemanticsVisitor* visitor, StructDecl* structDecl, ConstructorDecl** defaultCtorOut) { List ctorList; @@ -36,7 +42,7 @@ namespace Slang if (!ctor) return; ctorList.add(ctor); - if (ctor->members.getCount() != 0 || !defaultCtorOut) + if (ctor->members.getCount() != 0 && !allParamHaveInitExpr(ctor) || !defaultCtorOut) return; *defaultCtorOut = ctor; }; diff --git a/tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang b/tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang new file mode 100644 index 0000000000..98dfecfb62 --- /dev/null +++ b/tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang @@ -0,0 +1,24 @@ +//TEST:SIMPLE(filecheck=PASS): -target hlsl -entry computeMain -stage compute + +struct Test +{ + uint a; + uint b; + __init(int b = 16) + { + this.b = b; + } +}; + + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test test = Test(); + + // BUF: 16 + outputBuffer[0] = test.a; +} \ No newline at end of file From d82d68b5ab8a15430b85cbe3fc59910c1bc8c764 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 15 Aug 2024 14:31:01 -0400 Subject: [PATCH 005/100] Fixes 1. fix breaking tests which cannot be fixed by adding 'old style slang array init-list syntax' support, specifically for constructing a struct without an explicit '{}' 2. clean up tests --- source/slang/slang-check-conversion.cpp | 18 ++++++++++-- source/slang/slang-check-decl.cpp | 21 +++----------- source/slang/slang-check-impl.h | 1 + ...ds-compatible-array-initializer-list.slang | 29 +++++++++++++++++++ ...ynth-constructor-conflicting-default.slang | 5 ++-- .../dont-synth-internal-constructor.slang | 3 -- .../dont-synth-public-constructor.slang | 3 -- 7 files changed, 51 insertions(+), 29 deletions(-) create mode 100644 tests/language-feature/initializer-lists/backwards-compatible-array-initializer-list.slang diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 580ab5d5df..f056ad1709 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -465,15 +465,27 @@ namespace Slang maybeArgList.reserve(argCount); Index ioArgIndexMirror = ioArgIndex; UInt ioArgIndexCandidate = 0; + + // We also need to maximize the ctor arg count which is valid when processing ctor. + ctorList.stableSort( + [&](ConstructorDecl* a, ConstructorDecl* b) + { + return a->getParameters().getCount() > b->getParameters().getCount(); + } + ); + for (auto& ctor : ctorList) { auto ctorParamCount = ctor->getParameters().getCount(); - + if (ctorParamCount == 0) + continue; + ioArgIndexCandidate = ioArgIndexMirror; ioArgIndex = ctorParamCount; - // Skip if too many params expected by ctor - if (ctorParamCount != Index(argCount)) + // Skip processing ctor if too many params expected by ctor + // We need to allow non-exact param counts to support array to constructor init-list syntax + if (ctorParamCount > Index(argCount)) continue; List maybeCandidate; diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index bdade0f560..38c5718b64 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7679,7 +7679,7 @@ namespace Slang static bool _doesCtorExpectInitializerListUsage(ConstructorDecl* ctor) { - return ctor->containsOption(ConstructorTags::Synthesized) && ctor->getParameters().getCount() != 0; + return ctor->containsOption(ConstructorTags::Synthesized) && ctor->getParameters().getCount() != 0 && !allParamHaveInitExpr(ctor); } void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl) @@ -7818,23 +7818,10 @@ namespace Slang for (auto& m : structDecl->members) { auto varDeclBase = as(m); - // Static variables are initialized at start of runtime, not inside a constructor if (!varDeclBase - || varDeclBase->hasModifier()) - continue; - - // Default initializer initializes/zero's out all values, - // do this here. - auto intendedInitExpr = varDeclBase->initExpr; - if(structDeclInfo.defaultCtor == ctor && !intendedInitExpr) - { - auto defaultExpr = m_astBuilder->create(); - defaultExpr->type = varDeclBase->type.type; - intendedInitExpr = defaultExpr; - } - - if (!intendedInitExpr) + || varDeclBase->hasModifier() + || !varDeclBase->initExpr) continue; MemberExpr* memberExpr = m_astBuilder->create(); @@ -7847,7 +7834,7 @@ namespace Slang auto assign = m_astBuilder->create(); assign->left = memberExpr; - assign->right = intendedInitExpr; + assign->right = varDeclBase->initExpr; assign->loc = m->loc; auto stmt = m_astBuilder->create(); diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 6d94a4ac84..7da136c315 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -2934,6 +2934,7 @@ namespace Slang LookupOptions options); ConstructorDecl* _getDefaultCtor(StructDecl* structDecl); + bool allParamHaveInitExpr(ConstructorDecl* ctor); List _getCtorList(ASTBuilder* m_astBuilder, SemanticsVisitor* visitor, StructDecl* structDecl, ConstructorDecl** defaultCtorOut); bool DiagnoseIsAllowedInitExpr(VarDeclBase* varDecl, DiagnosticSink* sink); bool isDefaultInitializable(Type* varDeclType, VarDeclBase* associatedDecl); diff --git a/tests/language-feature/initializer-lists/backwards-compatible-array-initializer-list.slang b/tests/language-feature/initializer-lists/backwards-compatible-array-initializer-list.slang new file mode 100644 index 0000000000..c4a7da3296 --- /dev/null +++ b/tests/language-feature/initializer-lists/backwards-compatible-array-initializer-list.slang @@ -0,0 +1,29 @@ +//TEST:SIMPLE(filecheck=PASS): -target hlsl -entry computeMain -stage compute + +struct Test +{ + uint a; + uint b; +}; + + +//PASS: computeMain + +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test test[3] = {1, 2, 3, 4, 5, 6}; + + outputBuffer[0] = true + && test[0].a == 1 + && test[0].b == 2 + + && test[1].a == 1 + && test[1].b == 2 + + && test[2].a == 1 + && test[2].b == 2 + ; +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang b/tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang index 98dfecfb62..547b3cfb52 100644 --- a/tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang +++ b/tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang @@ -10,15 +10,14 @@ struct Test } }; - -//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer RWStructuredBuffer outputBuffer; +//PASS: computeMain + [numthreads(1, 1, 1)] void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) { Test test = Test(); - // BUF: 16 outputBuffer[0] = test.a; } \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/dont-synth-internal-constructor.slang b/tests/language-feature/initializer-lists/dont-synth-internal-constructor.slang index 4355b92f66..261c84a403 100644 --- a/tests/language-feature/initializer-lists/dont-synth-internal-constructor.slang +++ b/tests/language-feature/initializer-lists/dont-synth-internal-constructor.slang @@ -23,7 +23,6 @@ public struct Test } }; -//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer RWStructuredBuffer outputBuffer; [numthreads(1, 1, 1)] @@ -36,6 +35,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) && val1.nested1.val1 == 2 && val1.nested1.val2 == 2 ) ? 1 : 0; - -// BUF: 1 } \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/dont-synth-public-constructor.slang b/tests/language-feature/initializer-lists/dont-synth-public-constructor.slang index 800b20863f..646e522cd8 100644 --- a/tests/language-feature/initializer-lists/dont-synth-public-constructor.slang +++ b/tests/language-feature/initializer-lists/dont-synth-public-constructor.slang @@ -8,7 +8,6 @@ // ERROR: error 30500 import dont_synth_public_constructor_helper; -//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer RWStructuredBuffer outputBuffer; [numthreads(1, 1, 1)] @@ -21,6 +20,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) && val1.nested1.val1 == 2 && val1.nested1.val2 == 2 ) ? 1 : 0; - -// BUF: 1 } \ No newline at end of file From 892016af2cf5d1dd6f6dde12a6c8f4ee2e444c8e Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:48:32 -0400 Subject: [PATCH 006/100] fix bug and incorrect test 1. resolve generics which are associated to a struct instance during init list evaluation 2. fix autodiff test with incorrect init-list --- source/slang/slang-check-conversion.cpp | 12 +++++-- source/slang/slang-check-decl.cpp | 37 ++++++++++----------- tests/autodiff/auto-differential-type.slang | 4 +-- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index f056ad1709..c61858f6a5 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -306,7 +306,6 @@ namespace Slang { // TODO(tfoley): If we can compute the size of the array statically, // then we want to check that there aren't too many initializers present - auto toElementType = toArrayType->getElementType(); if(!toArrayType->isUnsized()) { @@ -491,11 +490,18 @@ namespace Slang List maybeCandidate; auto parameters = getParameters(m_astBuilder, ctor); auto parametersCount = parameters.getCount(); + for (auto index = coercedArgs.getCount(); index < parametersCount; index++) { auto ctorParam = parameters[index]; - auto paramType = getType(getASTBuilder(), ctorParam); - + auto paramType = ctorParam.getDecl()->type.type; + // Find 'equivlent typed' parameter if a member of the struct to allow subsitution + // in an attempt to resolve the generic of a type + // (required for vector/matrix/array resolution) + for (auto i : getMembersOfType(m_astBuilder, toStructDeclRef, MemberFilterStyle::Instance)) + if (i.getDecl()->type.type == paramType) + paramType = getType(m_astBuilder, i); + Expr* coercedArg = nullptr; _readValueFromInitializerList( paramType, diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 38c5718b64..285c4ab47e 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7815,39 +7815,36 @@ namespace Slang auto seqStmtChild = m_astBuilder->create(); seqStmtChild->stmts.reserve(structDecl->members.getCount()); - for (auto& m : structDecl->members) + for (auto varDeclBaseRef : getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance)) { - auto varDeclBase = as(m); - // Static variables are initialized at start of runtime, not inside a constructor - if (!varDeclBase - || varDeclBase->hasModifier() - || !varDeclBase->initExpr) + auto varDeclBase = varDeclBaseRef.getDecl(); + if (!varDeclBase->initExpr) continue; MemberExpr* memberExpr = m_astBuilder->create(); memberExpr->baseExpression = thisExpr; - memberExpr->declRef = m->getDefaultDeclRef(); + memberExpr->declRef = varDeclBase->getDefaultDeclRef(); memberExpr->scope = ctor->ownedScope; - memberExpr->loc = m->loc; - memberExpr->name = m->getName(); - memberExpr->type = DeclRefType::create(getASTBuilder(), m->getDefaultDeclRef()); + memberExpr->loc = varDeclBase->loc; + memberExpr->name = varDeclBase->getName(); + memberExpr->type = DeclRefType::create(getASTBuilder(), varDeclBase->getDefaultDeclRef()); auto assign = m_astBuilder->create(); assign->left = memberExpr; assign->right = varDeclBase->initExpr; - assign->loc = m->loc; + assign->loc = varDeclBase->loc; auto stmt = m_astBuilder->create(); stmt->expression = assign; - stmt->loc = m->loc; + stmt->loc = varDeclBase->loc; Expr* checkedMemberVarExpr; - if (cachedDeclToCheckedVar.containsKey(m)) - checkedMemberVarExpr = cachedDeclToCheckedVar[m]; + if (cachedDeclToCheckedVar.containsKey(varDeclBase)) + checkedMemberVarExpr = cachedDeclToCheckedVar[varDeclBase]; else { checkedMemberVarExpr = CheckTerm(memberExpr); - cachedDeclToCheckedVar.add({ m, checkedMemberVarExpr }); + cachedDeclToCheckedVar.add({ varDeclBase, checkedMemberVarExpr }); } if (!checkedMemberVarExpr->type.isLeftValue) continue; @@ -7881,7 +7878,7 @@ namespace Slang auto paramList = ctor->getParameters(); Index memberIndex = 0; - auto members = structDecl->getMembersOfType(); + auto members = getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance); auto seqStmt = _ensureCtorBodyIsSeqStmt(m_astBuilder, ctor); auto seqStmtChild = m_astBuilder->create(); @@ -7960,13 +7957,13 @@ namespace Slang paramExpr->type = paramType; paramExpr->loc = param->loc; - // skip static members - VarDeclBase* member = members[memberIndex++]; - while (member->hasModifier() || getDeclVisibility(member) < ctorVisibility) + // Skip static members + VarDeclBase* member = members[memberIndex++].getDecl(); + while (getDeclVisibility(member) < ctorVisibility) { // Should note be possible to be out of range unless compiler generated a synth-ctor wrong. SLANG_ASSERT(memberIndex < members.getCount()); - member = members[memberIndex++]; + member = members[memberIndex++].getDecl(); } MemberExpr* memberExpr = m_astBuilder->create(); diff --git a/tests/autodiff/auto-differential-type.slang b/tests/autodiff/auto-differential-type.slang index a253a25bb5..c0ba030782 100644 --- a/tests/autodiff/auto-differential-type.slang +++ b/tests/autodiff/auto-differential-type.slang @@ -50,8 +50,8 @@ A f(A a) void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) { { - A a = {1.0, 2.0}; - A.Differential b = {0.2}; + A a = { 1.0, 2.0 }; + A.Differential b = {0.2, 0}; dpA dpa = dpA(a, b); From 5755c0a9f505230593a15db8039eb82c227a6e2d Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:00:52 -0400 Subject: [PATCH 007/100] fix more tests with invalid init-lists --- tests/autodiff/differential-method-synthesis.slang | 2 +- tests/autodiff/getter-setter-multi.slang | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/autodiff/differential-method-synthesis.slang b/tests/autodiff/differential-method-synthesis.slang index e9385b78c1..aab92afb53 100644 --- a/tests/autodiff/differential-method-synthesis.slang +++ b/tests/autodiff/differential-method-synthesis.slang @@ -39,7 +39,7 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) { { A a = {1.0, 2.0}; - A.Differential b = {0.2}; + A.Differential b = {0.2, 0}; dpA dpa = dpA(a, b); outputBuffer[0] = __fwd_diff(f)(dpa).d.b.x; // Expect: 0 outputBuffer[1] = A.dadd(b, b).b.x; // Expect: 0.4 diff --git a/tests/autodiff/getter-setter-multi.slang b/tests/autodiff/getter-setter-multi.slang index 3f8257897f..85d4c7c64e 100644 --- a/tests/autodiff/getter-setter-multi.slang +++ b/tests/autodiff/getter-setter-multi.slang @@ -23,21 +23,21 @@ struct A : IDifferentiable [__unsafeForceInlineEarly] static Differential dzero() { - B b = {0.0}; + B b = {}; return b; } [__unsafeForceInlineEarly] static Differential dadd(Differential a, Differential b) { - B o = {a.z + b.z}; + B o = { a.z + b.z, {}}; return o; } [__unsafeForceInlineEarly] static Differential dmul(T a, Differential b) { - B o = {__realCast(a) * b.z}; + B o = { __realCast(a) * b.z, {}}; return o; } }; From f6d5bd3f80c3ac10b9f1d2f727e61fb340de653f Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 15 Aug 2024 17:40:39 -0400 Subject: [PATCH 008/100] fix swizzle causing a failiure with `checkExpr` to resolve an `Invoke` --- source/slang/slang-check-conversion.cpp | 5 +++- source/slang/slang-check-impl.h | 5 ++-- .../struct-swizzle-initializer-list.slang | 29 +++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index c61858f6a5..f198db7e8a 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -521,7 +521,10 @@ namespace Slang // Skip non-visible constructors. if (!isDeclVisible(ctor)) { - getSink()->diagnose(fromInitializerListExpr, Diagnostics::declIsNotVisible, ctor); + // if an exact argument match with our init-list we know the user meant to use a + // member-wise constructor, error + if(ctorParamCount == Index(argCount)) + getSink()->diagnose(fromInitializerListExpr, Diagnostics::declIsNotVisible, ctor); continue; } diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 7da136c315..f82dd0136a 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -2758,8 +2758,6 @@ namespace Slang CASE(DerefExpr) CASE(MakeRefExpr) - CASE(MatrixSwizzleExpr) - CASE(SwizzleExpr) CASE(OverloadedExpr) CASE(OverloadedExpr2) CASE(AggTypeCtorExpr) @@ -2771,6 +2769,9 @@ namespace Slang CASE(PartiallyAppliedGenericExpr) CASE(PackExpr) #undef CASE + + Expr* visitSwizzleExpr(SwizzleExpr* expr) { return expr; } + Expr* visitMatrixSwizzleExpr(MatrixSwizzleExpr* expr) { return expr; } Expr* visitStaticMemberExpr(StaticMemberExpr* expr); diff --git a/tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang b/tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang new file mode 100644 index 0000000000..6865073da4 --- /dev/null +++ b/tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang @@ -0,0 +1,29 @@ +//TEST:SIMPLE(filecheck=PASS): -target hlsl -entry computeMain -stage compute + +//PASS: computeMain + +RWStructuredBuffer outputBuffer; + +struct Test +{ + float3 a; + float3 b; + float2 c; +}; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + float3 position = {1, 2, 3}; + const Test test[3] = + { + mul(float4x4(1), float4(position, 1.f)).xyz, mul(float4x4(1), float4(position, 1.f)).xyz - mul(float4x4(1), float4(position, 1.f)).xyz, float2(2), + mul(float4x4(1), float4(position, 1.f)).xyz, mul(float4x4(1), float4(position, 1.f)).xyz - mul(float4x4(1), float4(position, 1.f)).xyz, float2(2), + mul(float4x4(1), float4(position, 1.f)).xyz, mul(float4x4(1), float4(position, 1.f)).xyz - mul(float4x4(1), float4(position, 1.f)).xyz, float2(2) + }; + outputBuffer[0] = true + && test[0].a[0] != 99 + && test[0].b[0] != 99 + && test[1].c[0] != 99 + ; +} \ No newline at end of file From 045e27a4aa534540897141cbd43883af28ec75a4 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:47:19 -0400 Subject: [PATCH 009/100] init expr with default ctor is now more restrictive due to current limitations. --- source/slang/slang-check-decl.cpp | 40 ++++++++++++++++++------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 285c4ab47e..b884748523 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2011,25 +2011,31 @@ namespace Slang } else if(overloadContext.bestCandidate) { - // If we are in the single-candidate case, then we again - // want to ignore the case where that candidate wasn't - // actually applicable, because declaring a variable - // of a type that *doesn't* have a default initializer - // isn't actually an error. - // - if (overloadContext.bestCandidate->status != OverloadCandidate::Status::Applicable) - { - getShared()->cacheImplicitCastMethod(key, ImplicitCastMethod{}); - } - else + // We want to be sure we are not trying to set a uninitialized value to initialized + // if the ctor was synthisized by the compiler (without a user knowing). + auto ctorBestCandidate = as(overloadContext.bestCandidate->item.declRef.getDecl()); + if (!ctorBestCandidate || !ctorBestCandidate->containsOption(ConstructorTags::Synthesized)) { - // If we had a single best candidate *and* it was applicable, - // then we use it to construct a new initial-value expression - // for the variable, that will be used for all downstream - // code generation. + // If we are in the single-candidate case, then we again + // want to ignore the case where that candidate wasn't + // actually applicable, because declaring a variable + // of a type that *doesn't* have a default initializer + // isn't actually an error. // - varDecl->initExpr = CompleteOverloadCandidate(overloadContext, *overloadContext.bestCandidate); - getShared()->cacheImplicitCastMethod(key, ImplicitCastMethod{*overloadContext.bestCandidate, 0}); + if (overloadContext.bestCandidate->status != OverloadCandidate::Status::Applicable) + { + getShared()->cacheImplicitCastMethod(key, ImplicitCastMethod{}); + } + else + { + // If we had a single best candidate *and* it was applicable, + // then we use it to construct a new initial-value expression + // 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 }); + } } } } From 4c36d3af8cd69103b66c49b8292deb4088267453 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:31:38 -0400 Subject: [PATCH 010/100] Revert "init expr with default ctor is now more restrictive due to current limitations." Revert because it will break code, instead just check more generally for 0, if we don't want the "everything does an 'init'" logic this can be changes later. --- source/slang/slang-check-decl.cpp | 40 ++++++++----------- .../zero-initialize/shared-memory.slang | 4 +- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index b884748523..285c4ab47e 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2011,31 +2011,25 @@ namespace Slang } else if(overloadContext.bestCandidate) { - // We want to be sure we are not trying to set a uninitialized value to initialized - // if the ctor was synthisized by the compiler (without a user knowing). - auto ctorBestCandidate = as(overloadContext.bestCandidate->item.declRef.getDecl()); - if (!ctorBestCandidate || !ctorBestCandidate->containsOption(ConstructorTags::Synthesized)) + // If we are in the single-candidate case, then we again + // want to ignore the case where that candidate wasn't + // actually applicable, because declaring a variable + // of a type that *doesn't* have a default initializer + // isn't actually an error. + // + if (overloadContext.bestCandidate->status != OverloadCandidate::Status::Applicable) + { + getShared()->cacheImplicitCastMethod(key, ImplicitCastMethod{}); + } + else { - // If we are in the single-candidate case, then we again - // want to ignore the case where that candidate wasn't - // actually applicable, because declaring a variable - // of a type that *doesn't* have a default initializer - // isn't actually an error. + // If we had a single best candidate *and* it was applicable, + // then we use it to construct a new initial-value expression + // for the variable, that will be used for all downstream + // code generation. // - if (overloadContext.bestCandidate->status != OverloadCandidate::Status::Applicable) - { - getShared()->cacheImplicitCastMethod(key, ImplicitCastMethod{}); - } - else - { - // If we had a single best candidate *and* it was applicable, - // then we use it to construct a new initial-value expression - // 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 }); - } + varDecl->initExpr = CompleteOverloadCandidate(overloadContext, *overloadContext.bestCandidate); + getShared()->cacheImplicitCastMethod(key, ImplicitCastMethod{*overloadContext.bestCandidate, 0}); } } } diff --git a/tests/language-feature/zero-initialize/shared-memory.slang b/tests/language-feature/zero-initialize/shared-memory.slang index 39243f796a..f64a04cd35 100644 --- a/tests/language-feature/zero-initialize/shared-memory.slang +++ b/tests/language-feature/zero-initialize/shared-memory.slang @@ -6,8 +6,8 @@ RWStructuredBuffer outputBuffer; // GLSL-NOT: error 30623 // HLSL-NOT: error 30623 -// GLSL-NOT: globalMem{{.*}} = -// HLSL-NOT: globalMem{{.*}} = +// GLSL-NOT: {{.*}}={{.*}}0{{.}}; +// HLSL-NOT: {{.*}}={{.*}}0{{.}}; groupshared uint globalMem; From cbe95fbf7d814748f02891c7506117cb7fbb6dd9 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 15 Aug 2024 23:01:43 -0400 Subject: [PATCH 011/100] try removing null default-ctor construction logic due to causing failiures remove all null default-ctor's like before, instead though redesign the hacky overload resolution into ctor such that it works: 1. resolveInvoke properly culls useless overloads 2. This stops spirious generation of empty init's (side-effect if we generate a real ctor) 3. This stops lots of warnings since we don't have a ctor that init's nothing --- source/slang/slang-check-decl.cpp | 20 ++++++++++++ source/slang/slang-check-overload.cpp | 47 ++++++++++++++++++--------- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 285c4ab47e..5cd1405c9f 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7987,6 +7987,26 @@ namespace Slang } seqStmt->stmts.insert(ctorInfo.insertOffset++, seqStmtChild); } + + // compiler generated ctor may be destroyed if unused + if(structDeclInfo.defaultCtor + && structDeclInfo.defaultCtor->containsOption(ConstructorTags::Synthesized)) + { + bool destroy = false; + if (!structDeclInfo.defaultCtor->body) + destroy = true; + else if (auto block = as(structDeclInfo.defaultCtor->body)) + { + if (as(block->body)->stmts.getCount() == 0) + destroy = true; + } + if (destroy) + { + structDecl->members.remove(structDeclInfo.defaultCtor); + structDecl->invalidateMemberDictionary(); + structDecl->buildMemberDictionary(); + } + } } void SemanticsDeclHeaderVisitor::cloneModifiers(Decl* dest, Decl* src) diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 1c8ee6bef7..41f17335d7 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -1172,6 +1172,10 @@ namespace Slang LookupResultItem const& left, LookupResultItem const& right) { + // Equal lookup-items, choose the left one. + if (left.declRef == right.declRef) + return 1; + // It is possible for lookup to return both an interface requirement // and the concrete function that satisfies that requirement. // We always want to favor a concrete method over an interface @@ -1184,7 +1188,7 @@ namespace Slang // this kind of "is an override of ..." information on declarations // directly (it is only visible through the requirement witness // information for inheritance declarations). - // + auto leftDeclRefParent = left.declRef.getParent(); auto rightDeclRefParent = right.declRef.getParent(); bool leftIsInterfaceRequirement = isInterfaceRequirement(left.declRef.getDecl()); @@ -1432,7 +1436,10 @@ namespace Slang return overloadRankDiff; } - return 0; + // Since some overload logic requires a simplified overload item list + // we require some comparison to remove clearly invalid overload candidates + // to avoid errors. + return CompareLookupResultItems(left->item, right->item); } void SemanticsVisitor::AddOverloadCandidateInner( @@ -2417,6 +2424,28 @@ namespace Slang } else if (context.bestCandidate) { + // We allow a special case for when `funcExpr` is expected to be a Default initializer + // but none exist. Note, we cannot just create a default initializer for every variable + // since then we are introducing initialization to every variable through an indirect + // init returning data. + if (context.argCount == 0) + { + auto oldMode = context.mode; + context.mode = OverloadResolveContext::Mode::JustTrying; + bool arityIsValid = TryCheckOverloadCandidateArity(context, *context.bestCandidate); + context.mode = oldMode; + + if (!arityIsValid) + { + auto initListExpr = m_astBuilder->create(); + initListExpr->loc = expr->loc; + initListExpr->type = m_astBuilder->getInitializerListType(); + Expr* outExpr = nullptr; + if (_coerceInitializerList(context.bestCandidate->resultType, &outExpr, initListExpr)) + return outExpr; + } + } + // There was one best candidate, even if it might not have been // applicable in the end. // We will report errors for this one candidate, then, to give @@ -2439,20 +2468,6 @@ namespace Slang } } - if (auto typetype = as(typeExpr->type)) - { - // We allow a special case when `funcExpr` represents a composite type, - // in which case we will try to construct the type via memberwise assignment from the arguments. - // - auto initListExpr = m_astBuilder->create(); - initListExpr->loc = expr->loc; - initListExpr->args.addRange(expr->arguments); - initListExpr->type = m_astBuilder->getInitializerListType(); - Expr* outExpr = nullptr; - if (_coerceInitializerList(typetype->getType(), &outExpr, initListExpr)) - return outExpr; - } - // Nothing at all was found that we could even consider invoking. // In all other cases, this is an error. getSink()->diagnose(expr->functionExpr, Diagnostics::expectedFunction, funcExprType); From f8bf220d011c9dd9d1c46c374ba5c046cd66e51c Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 15 Aug 2024 23:12:28 -0400 Subject: [PATCH 012/100] undo some code removal --- source/slang/slang-check-overload.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 41f17335d7..673891f72b 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -2468,6 +2468,20 @@ namespace Slang } } + if (auto typetype = as(typeExpr->type)) + { + // We allow a special case when `funcExpr` represents a composite type, + // in which case we will try to construct the type via memberwise assignment from the arguments. + // + auto initListExpr = m_astBuilder->create(); + initListExpr->loc = expr->loc; + initListExpr->args.addRange(expr->arguments); + initListExpr->type = m_astBuilder->getInitializerListType(); + Expr* outExpr = nullptr; + if (_coerceInitializerList(typetype->getType(), &outExpr, initListExpr)) + return outExpr; + } + // Nothing at all was found that we could even consider invoking. // In all other cases, this is an error. getSink()->diagnose(expr->functionExpr, Diagnostics::expectedFunction, funcExprType); From 1e7819a7968af875d7af88f852e3e955af227c8f Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:00:41 -0400 Subject: [PATCH 013/100] make a few additions/changes to init list logic: 1. allow a more formalized init-list logic for flattened init-lists's 2. fixing invalid tests --- source/slang/slang-check-conversion.cpp | 61 +++++++++++-------- source/slang/slang-check-decl.cpp | 36 +++++------ source/slang/slang-diagnostic-defs.h | 2 +- tests/autodiff/reverse-addr-eliminate.slang | 4 +- tests/bugs/gh-3601.slang | 2 +- tests/compute/struct-default-init.slang | 15 +++++ ...izer-list.slang => cstyle-init-list.slang} | 0 .../dont-allow-cstyle-init-list-1.slang | 31 ++++++++++ .../dont-allow-cstyle-init-list-2.slang | 34 +++++++++++ .../zero-initialize/shared-memory.slang | 4 +- tests/metal/sv_target-complex-1.slang | 2 +- tests/spirv/pointer.slang | 2 +- .../unit-test-decl-tree-reflection.cpp | 6 +- 13 files changed, 147 insertions(+), 52 deletions(-) rename tests/language-feature/initializer-lists/{backwards-compatible-array-initializer-list.slang => cstyle-init-list.slang} (100%) create mode 100644 tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-1.slang create mode 100644 tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-2.slang diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index f198db7e8a..6c9da739fd 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -213,6 +213,29 @@ namespace Slang return nullptr; } + bool _allowCStyleInitList(List ctorList) + { + bool foundNonDefaultInit = false; + for (auto i : ctorList) + { + // Default ctor do not affect this logic. + if (i->getParameters().getCount() == 0) + continue; + + // Cannot contain user defined ctor which is a non default ctor + if (!i->containsOption(ConstructorTags::Synthesized)) + return false; + + // Cannot contain 2+ non-default init's, this is ambigious for a c-style init list: + // `MyStruct[3] tmp = {1,2, 1,2, 1,2};` + // if `__init(int, int)` and `__init(int)` were both defined we would have ambiguity. + if (foundNonDefaultInit) + return false; + foundNonDefaultInit = true; + } + return true; + } + bool SemanticsVisitor::_readAggregateValueFromInitializerList( Type* inToType, Expr** outToExpr, @@ -443,15 +466,16 @@ namespace Slang { auto toTypeDeclRef = toDeclRefType->getDeclRef(); // Trying to initialize a `struct` type given an initializer list. + // We will try to coerce the initializer list into a constructor. if(auto toStructDeclRef = toTypeDeclRef.as()) { auto toStructDecl = toStructDeclRef.getDecl(); ensureDecl(toStructDecl, DeclCheckState::DefaultConstructorReadyForUse); - // We will try to coerce the initializer list (in order) into a constructor. List ctorList = _getCtorList(this->getASTBuilder(), this, toStructDecl, nullptr); - - // Easy case of default constructor + bool allowCStyleInitList = _allowCStyleInitList(ctorList); + + // Easy case of default constructor or equivalent if (argCount == 0) { if (outToExpr) @@ -465,26 +489,19 @@ namespace Slang Index ioArgIndexMirror = ioArgIndex; UInt ioArgIndexCandidate = 0; - // We also need to maximize the ctor arg count which is valid when processing ctor. - ctorList.stableSort( - [&](ConstructorDecl* a, ConstructorDecl* b) - { - return a->getParameters().getCount() > b->getParameters().getCount(); - } - ); - for (auto& ctor : ctorList) { + // Don't try to init default ctor with this logic auto ctorParamCount = ctor->getParameters().getCount(); if (ctorParamCount == 0) continue; ioArgIndexCandidate = ioArgIndexMirror; ioArgIndex = ctorParamCount; - - // Skip processing ctor if too many params expected by ctor - // We need to allow non-exact param counts to support array to constructor init-list syntax - if (ctorParamCount > Index(argCount)) + + // if allowCStyleInitList, process any ctor which comes next. ioArgIndex may not be 0 + // if !allowCStyleInitList, process any ctor that exactly matched our argument count. ioArgIndex must start at 0. + if (!allowCStyleInitList && ctorParamCount != Index(argCount)) continue; List maybeCandidate; @@ -495,9 +512,6 @@ namespace Slang { auto ctorParam = parameters[index]; auto paramType = ctorParam.getDecl()->type.type; - // Find 'equivlent typed' parameter if a member of the struct to allow subsitution - // in an attempt to resolve the generic of a type - // (required for vector/matrix/array resolution) for (auto i : getMembersOfType(m_astBuilder, toStructDeclRef, MemberFilterStyle::Instance)) if (i.getDecl()->type.type == paramType) paramType = getType(m_astBuilder, i); @@ -505,7 +519,7 @@ namespace Slang Expr* coercedArg = nullptr; _readValueFromInitializerList( paramType, - outToExpr ? &coercedArg : nullptr, + &coercedArg, fromInitializerListExpr, ioArgIndexCandidate); @@ -515,7 +529,7 @@ namespace Slang break; } - if (maybeArgList.getCount() != ctor->getParameters().getCount()) + if (maybeArgList.getCount() != ctorParamCount) continue; // Skip non-visible constructors. @@ -551,9 +565,8 @@ namespace Slang constructorExpr->type = toType; *outToExpr = CheckExpr(constructorExpr); - - return true; } + return true; } // If we have a generic being compared to another generic (with different generic arguments) @@ -561,11 +574,11 @@ namespace Slang // // MyStruct tmp = {MyStructBase(), 1}; // assume 'U' is unresolved at this point in time but equal to T // - // // To handle this since this is not verifiable coerce logic: // 1. We need to ensure we don't have any matching constructors // 2. if '1.' is true we can assign the possibly compatible generics and let generic resolution diagnose // if something makes zero sense. + if (auto toGenericType = _getGenericAppDeclRefType(toType)) { auto arg = fromInitializerListExpr->args[ioArgIndexMirror]; @@ -644,7 +657,7 @@ namespace Slang { if( outToExpr ) { - getSink()->diagnose(fromInitializerListExpr, Diagnostics::tooManyInitializers, argCount); + getSink()->diagnose(fromInitializerListExpr, Diagnostics::tooManyInitializers, argCount, toType); } } diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 5cd1405c9f..36fa74c6c2 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1814,7 +1814,7 @@ namespace Slang SemanticsDeclVisitorBase* visitor, ASTBuilder* m_astBuilder, AggTypeDecl* decl, - List&& argList, + List&& argList, DeclVisibility visibility) { auto ctor = m_astBuilder->create(); @@ -1850,7 +1850,7 @@ namespace Slang for (auto arg : argList) { auto param = m_astBuilder->create(); - param->type = (TypeExp)arg; + param->type = (TypeExp)arg->type; param->parentDecl = ctor; param->loc = ctor->loc; ctor->members.add(param); @@ -7972,7 +7972,7 @@ namespace Slang memberExpr->scope = ctor->ownedScope; memberExpr->loc = member->loc; memberExpr->name = member->getName(); - memberExpr->type = DeclRefType::create(getASTBuilder(), member->getDefaultDeclRef()); + memberExpr->type = DeclRefType::create(getASTBuilder(), memberExpr->declRef); auto assign = m_astBuilder->create(); assign->left = memberExpr; @@ -7988,7 +7988,7 @@ namespace Slang seqStmt->stmts.insert(ctorInfo.insertOffset++, seqStmtChild); } - // compiler generated ctor may be destroyed if unused + // Compiler generated ctor may be destroyed if(structDeclInfo.defaultCtor && structDeclInfo.defaultCtor->containsOption(ConstructorTags::Synthesized)) { @@ -10224,7 +10224,7 @@ namespace Slang static ConstructorDecl* _tryToGenerateCtorWithArgList( SemanticsDeclVisitorBase* visitor, ASTBuilder* astBuilder, - List&& args, + List&& args, List& existingCtorList, StructDecl* structDecl, DeclVisibility visibility) @@ -10250,7 +10250,7 @@ namespace Slang { auto newCtorArg = args[i]; auto existingCtorArg = existingCtorArgs[i]; - if (visitor->getConversionCost(newCtorArg, existingCtorArg->getType()) == kConversionCost_Impossible) + if (visitor->getConversionCost(newCtorArg->getType(), existingCtorArg->getType()) == kConversionCost_Impossible) { equalCtor = false; break; @@ -10284,11 +10284,11 @@ namespace Slang // Add an empty constructor for all combinations of visibility and access // which is possible: // 1. public constructor - usable *outside class scope* in a *different module* - List publicCtorArgs; + List publicCtorArgs; // 2. public-internal constructor - usable *outside class scope* in the *same module* - List publicInternalCtorArgs; + List publicInternalCtorArgs; // 3. public-private-internal constructor - usable *inside class scope* in the *same module* - List publicPrivateInternalCtorArgs; + List publicPrivateInternalCtorArgs; // Harvest parameters which map to the base type ctor. if(auto baseStructRef = findBaseStructDeclRef(m_astBuilder, structDecl)) @@ -10321,12 +10321,12 @@ namespace Slang { for (auto i : ctorForPublic->getParameters()) { - publicCtorArgs.add(i->type); + publicCtorArgs.add(i); } for (auto i : ctorForInternal->getParameters()) { - publicInternalCtorArgs.add(i->type); - publicPrivateInternalCtorArgs.add(i->type); + publicInternalCtorArgs.add(i); + publicPrivateInternalCtorArgs.add(i); } } } @@ -10347,20 +10347,20 @@ namespace Slang switch (declVisibility) { case DeclVisibility::Private: - publicPrivateInternalCtorArgs.add(varDeclType); + publicPrivateInternalCtorArgs.add(varDecl); if(!varDecl->initExpr) maxVisibilityToGenerateCtor = DeclVisibility::Private; break; case DeclVisibility::Internal: - publicPrivateInternalCtorArgs.add(varDeclType); - publicInternalCtorArgs.add(varDeclType); + publicPrivateInternalCtorArgs.add(varDecl); + publicInternalCtorArgs.add(varDecl); if (!varDecl->initExpr) maxVisibilityToGenerateCtor = DeclVisibility::Internal; break; case DeclVisibility::Public: - publicPrivateInternalCtorArgs.add(varDeclType); - publicInternalCtorArgs.add(varDeclType); - publicCtorArgs.add(varDeclType); + publicPrivateInternalCtorArgs.add(varDecl); + publicInternalCtorArgs.add(varDecl); + publicCtorArgs.add(varDecl); break; default: // Unknown visibility diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index bae3508d59..5f77bfdea7 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -517,7 +517,7 @@ DIAGNOSTIC(30400, Error, genericTypeNeedsArgs, "generic type '$0' used without a DIAGNOSTIC(30401, Error, invalidTypeForConstraint, "type '$0' cannot be used as a constraint.") // 305xx: initializer lists -DIAGNOSTIC(30500, Error, tooManyInitializers, "cannot find matching constructor to call with arguments count of '$0'") +DIAGNOSTIC(30500, Error, tooManyInitializers, "cannot find matching constructor to call with arguments count of '$0' for '$1'") DIAGNOSTIC(30501, Error, cannotUseInitializerListForArrayOfUnknownSize, "cannot use initializer list for array of statically unknown size '$0'") DIAGNOSTIC(30502, Error, cannotUseInitializerListForVectorOfUnknownSize, "cannot use initializer list for vector of statically unknown size '$0'") DIAGNOSTIC(30503, Error, cannotUseInitializerListForMatrixOfUnknownSize, "cannot use initializer list for matrix of statically unknown size '$0' rows") diff --git a/tests/autodiff/reverse-addr-eliminate.slang b/tests/autodiff/reverse-addr-eliminate.slang index 49f34a6e35..e49a0f691e 100644 --- a/tests/autodiff/reverse-addr-eliminate.slang +++ b/tests/autodiff/reverse-addr-eliminate.slang @@ -53,7 +53,9 @@ A f(A a, int i) [numthreads(1, 1, 1)] void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) { - A a = {1.0, 2.0}; + A a; + a.x = 1; + a.y = 2; var dpa = diffPair(a); diff --git a/tests/bugs/gh-3601.slang b/tests/bugs/gh-3601.slang index d12b480acf..8852cb9658 100644 --- a/tests/bugs/gh-3601.slang +++ b/tests/bugs/gh-3601.slang @@ -42,7 +42,7 @@ void main(int id : SV_DispatchThreadID) *pData1 = 3; *(int2*)pData = int2(1, 2); pData1[-1] = 2; - buffer[0].pNext[1] = {5}; + buffer[0].pNext[1] = {5, 0}; // CHECK: OpConvertPtrToU // CHECK: OpINotEqual if (pData1) diff --git a/tests/compute/struct-default-init.slang b/tests/compute/struct-default-init.slang index dc0e0218af..5a0d0e6930 100644 --- a/tests/compute/struct-default-init.slang +++ b/tests/compute/struct-default-init.slang @@ -7,6 +7,21 @@ struct Test int b = 1; int c = 0; int d = 1 + 1; + __init(int a_in) + { + a = a_in; + } + __init(int a_in, int b_in) + { + a = a_in; + b = b_in; + } + __init(int a_in, int b_in, int c_in) + { + a = a_in; + b = b_in; + c = c_in; + } } int test(int inVal) diff --git a/tests/language-feature/initializer-lists/backwards-compatible-array-initializer-list.slang b/tests/language-feature/initializer-lists/cstyle-init-list.slang similarity index 100% rename from tests/language-feature/initializer-lists/backwards-compatible-array-initializer-list.slang rename to tests/language-feature/initializer-lists/cstyle-init-list.slang diff --git a/tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-1.slang b/tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-1.slang new file mode 100644 index 0000000000..682eaac3aa --- /dev/null +++ b/tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-1.slang @@ -0,0 +1,31 @@ +//TEST:SIMPLE(filecheck=ERROR): -target hlsl -entry computeMain -stage compute + +public struct Test +{ + // note: we need an initExpr here for an error because else Slang will disallow + // synthisis of a 'public' constructor, meaning nothing has to fail. + internal uint a = 5; + public uint b; +}; + + +//ERROR: error 30500 + +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test test[3] = {1, 2, 3, 4, 5, 6}; + + outputBuffer[0] = true + && test[0].a == 1 + && test[0].b == 2 + + && test[1].a == 1 + && test[1].b == 2 + + && test[2].a == 1 + && test[2].b == 2 + ; +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-2.slang b/tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-2.slang new file mode 100644 index 0000000000..903d9c164d --- /dev/null +++ b/tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-2.slang @@ -0,0 +1,34 @@ +//TEST:SIMPLE(filecheck=ERROR): -target hlsl -entry computeMain -stage compute + +struct Test +{ + uint a; + uint b; + __init(int a_in, int b_in) + { + a_in = 0; + b_in = 0; + } +}; + + +//ERROR: error 30500 + +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test test[3] = {1, 2, 3, 4, 5, 6}; + + outputBuffer[0] = true + && test[0].a == 1 + && test[0].b == 2 + + && test[1].a == 1 + && test[1].b == 2 + + && test[2].a == 1 + && test[2].b == 2 + ; +} \ No newline at end of file diff --git a/tests/language-feature/zero-initialize/shared-memory.slang b/tests/language-feature/zero-initialize/shared-memory.slang index f64a04cd35..39243f796a 100644 --- a/tests/language-feature/zero-initialize/shared-memory.slang +++ b/tests/language-feature/zero-initialize/shared-memory.slang @@ -6,8 +6,8 @@ RWStructuredBuffer outputBuffer; // GLSL-NOT: error 30623 // HLSL-NOT: error 30623 -// GLSL-NOT: {{.*}}={{.*}}0{{.}}; -// HLSL-NOT: {{.*}}={{.*}}0{{.}}; +// GLSL-NOT: globalMem{{.*}} = +// HLSL-NOT: globalMem{{.*}} = groupshared uint globalMem; diff --git a/tests/metal/sv_target-complex-1.slang b/tests/metal/sv_target-complex-1.slang index a830ff3d26..f21b417ca6 100644 --- a/tests/metal/sv_target-complex-1.slang +++ b/tests/metal/sv_target-complex-1.slang @@ -30,5 +30,5 @@ struct Output [shader("fragment")] Output fragmentMain() { - return { float4(1), {float4(2)}, float4(3) }; + return { float4(1), { float4(2) }, float4(3), {} }; } \ No newline at end of file diff --git a/tests/spirv/pointer.slang b/tests/spirv/pointer.slang index 03ca3fb394..51d26f47df 100644 --- a/tests/spirv/pointer.slang +++ b/tests/spirv/pointer.slang @@ -39,7 +39,7 @@ void main(int id : SV_DispatchThreadID) *pData1 = 3; *(int2*)pData = int2(1, 2); pData1[-1] = 2; - buffer[0].pNext[1] = {5}; + buffer[0].pNext[1] = {5, 0}; // CHECK: OpConvertPtrToU // CHECK: OpINotEqual if (pData1) 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 36b0306b25..aaf560200d 100644 --- a/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp +++ b/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp @@ -103,16 +103,16 @@ SLANG_UNIT_TEST(declTreeReflection) SLANG_CHECK(moduleDeclReflection->getKind() == slang::DeclReflection::Kind::Module); SLANG_CHECK(moduleDeclReflection->getChildrenCount() == 7); - // First declaration should be a struct with 1 variable and 2 constructor (memberwise and default ctor) + // First declaration should be a struct with 1 variable and 1 constructor (memberwise ctor) auto firstDecl = moduleDeclReflection->getChild(0); SLANG_CHECK(firstDecl->getKind() == slang::DeclReflection::Kind::Struct); - SLANG_CHECK(firstDecl->getChildrenCount() == 3); + SLANG_CHECK(firstDecl->getChildrenCount() == 2); { slang::TypeReflection* type = firstDecl->getType(); SLANG_CHECK(getTypeFullName(type) == "MyFuncPropertyAttribute"); - // Check the field of the struct + // Check the field of the struct. SLANG_CHECK(type->getFieldCount() == 1); auto field = type->getFieldByIndex(0); SLANG_CHECK(UnownedStringSlice(field->getName()) == "v"); From 1e4ec3527a316e0e423100155019d24f361a999f Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:03:40 -0400 Subject: [PATCH 014/100] remove unused var --- source/slang/slang-check-decl.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 36fa74c6c2..44f90fa83b 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -10342,7 +10342,6 @@ namespace Slang auto varDecl = varDeclRef.getDecl(); ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); auto declVisibility = getDeclVisibility(varDecl); - auto varDeclType = varDecl->type; switch (declVisibility) { From 95e719d47e37392c870c2a62b89740d37cbac2fc Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 16 Aug 2024 17:54:20 -0400 Subject: [PATCH 015/100] cleanup some tests, logic and auto-documentation code 1. clean-up documentation tests 2. fix recursive type crash with uninitialized value checks 3. fully disallow synth object printing rather than partially for auto-documentation code. --- source/slang/slang-doc-ast.cpp | 9 ++++- source/slang/slang-doc-ast.h | 2 + source/slang/slang-doc-markdown-writer.cpp | 2 + .../slang-ir-use-uninitialized-values.cpp | 3 ++ tests/diagnostics/mismatching-types.slang | 22 +++++------ .../diagnostics/variable-redeclaration.slang | 14 ++++++- .../variable-redeclaration.slang.expected | 38 ------------------- 7 files changed, 38 insertions(+), 52 deletions(-) delete mode 100644 tests/diagnostics/variable-redeclaration.slang.expected diff --git a/source/slang/slang-doc-ast.cpp b/source/slang/slang-doc-ast.cpp index 172f31b324..1bc33bf192 100644 --- a/source/slang/slang-doc-ast.cpp +++ b/source/slang/slang-doc-ast.cpp @@ -47,9 +47,14 @@ namespace Slang { } } +bool doWeDocDecl(Decl* decl) +{ + return !getText(decl->getName()).startsWith("$__syn") && !decl->findModifier(); +} + static void _addDeclRec(Decl* decl, List& outDecls) { - if (decl == nullptr) + if (decl == nullptr || !doWeDocDecl(decl)) { return; } @@ -109,7 +114,7 @@ SlangResult ASTMarkupUtil::extract(ModuleDecl* moduleDecl, SourceManager* source item.searchStyle = getSearchStyle(decl); // Don't generate documentation for synthesized members. - if (getText(decl->getName()).startsWith("$__syn")) + if (!doWeDocDecl(decl)) item.searchStyle = DocMarkupExtractor::SearchStyle::None; } diff --git a/source/slang/slang-doc-ast.h b/source/slang/slang-doc-ast.h index 25c39d9d38..34bba8b7b8 100644 --- a/source/slang/slang-doc-ast.h +++ b/source/slang/slang-doc-ast.h @@ -87,6 +87,8 @@ struct ASTMarkupUtil static SlangResult extract(ModuleDecl* moduleDecl, SourceManager* sourceManager, DiagnosticSink* sink, ASTMarkup* outMarkup, bool searchOrindaryComments = false); }; +bool doWeDocDecl(Decl* decl); + } // namespace Slang #endif diff --git a/source/slang/slang-doc-markdown-writer.cpp b/source/slang/slang-doc-markdown-writer.cpp index f295741804..e5800d0ee3 100644 --- a/source/slang/slang-doc-markdown-writer.cpp +++ b/source/slang/slang-doc-markdown-writer.cpp @@ -1070,6 +1070,8 @@ void DocMarkdownWriter::writeAggType(const ASTMarkup::Entry& entry, AggTypeDeclB List uniqueMethods; for (const auto& [_, decl] : memberDict) { + if (!doWeDocDecl(decl)) + continue; CallableDecl* callableDecl = as(decl); if (callableDecl && isVisible(callableDecl)) { diff --git a/source/slang/slang-ir-use-uninitialized-values.cpp b/source/slang/slang-ir-use-uninitialized-values.cpp index b8dfcc33cb..f82b718be6 100644 --- a/source/slang/slang-ir-use-uninitialized-values.cpp +++ b/source/slang/slang-ir-use-uninitialized-values.cpp @@ -179,6 +179,9 @@ namespace Slang // Avoid the recursive step if its a // recursive structure like a linked list IRType* ptype = ptr->getValueType(); + if (auto spec = as(ptype)) + if(auto resolvedType = as(resolveSpecialization(spec))) + ptype = resolvedType; return (ptype != upper) && canIgnoreType(ptype, upper); } diff --git a/tests/diagnostics/mismatching-types.slang b/tests/diagnostics/mismatching-types.slang index 15fc1d0e3f..edd4e33750 100644 --- a/tests/diagnostics/mismatching-types.slang +++ b/tests/diagnostics/mismatching-types.slang @@ -1,5 +1,5 @@ // mismatching-types.slang -//DIAGNOSTIC_TEST:SIMPLE:-target hlsl +//TEST:SIMPLE(filecheck=CHECK): -target hlsl Texture1D tex; @@ -47,21 +47,21 @@ void main(uint3 dispatchThreadID : SV_DispatchThreadID) NonGenericOuter c; NonGenericOuter.GenericInner d; - // expected an expression of type 'GenericOuter', got 'int' +//CHECK: tests/diagnostics/mismatching-types.slang(51): error 30019: expected an expression of type 'GenericOuter', got 'int' a = 0; - // expected an expression of type 'GenericOuter.GenericInner', got 'int' +//CHECK: tests/diagnostics/mismatching-types.slang(53): error 30019: expected an expression of type 'GenericOuter.GenericInner', got 'int' a.g = 0; - // expected an expression of type 'GenericOuter.NonGenericInner', got 'int' +//CHECK: tests/diagnostics/mismatching-types.slang(55): error 30019: expected an expression of type 'GenericOuter.NonGenericInner', got 'int' a.ng = 0; - // expected an expression of type 'GenericOuter.GenericInner', got 'GenericOuter.GenericInner' +//CHECK: tests/diagnostics/mismatching-types.slang(57): error 30019: expected an expression of type 'GenericOuter.GenericInner', got 'GenericOuter.GenericInner' a.g = b.g; - // expected an expression of type 'GenericOuter.NonGenericInner', got 'GenericOuter.NonGenericInner' +//CHECK: tests/diagnostics/mismatching-types.slang(59): error 30019: expected an expression of type 'GenericOuter.NonGenericInner', got 'GenericOuter.NonGenericInner' a.ng = b.ng; - // expected an expression of type 'NonGenericOuter.GenericInner', got 'int' +//CHECK: tests/diagnostics/mismatching-types.slang(61): error 30019: expected an expression of type 'GenericInner', got 'int' c.i = 0; - // expected an expression of type 'NonGenericOuter.GenericInner', got 'NonGenericOuter.GenericInner' +//CHECK: tests/diagnostics/mismatching-types.slang(63): error 30019: expected an expression of type 'GenericInner', got 'GenericInner' c.i = c.f; - // expected an expression of type 'NonGenericOuter.GenericInner.ReallyNested', got 'int' +//CHECK: tests/diagnostics/mismatching-types.slang(65): error 30019: expected an expression of type 'GenericInner.ReallyNested', got 'int' c.i.n = 0; // OK c.i.n.val = 0; @@ -70,8 +70,8 @@ void main(uint3 dispatchThreadID : SV_DispatchThreadID) // OK c.i = d; - // expected an expression of type 'Texture1D', got 'Texture1D' +//CHECK: tests/diagnostics/mismatching-types.slang(74): error 30019: expected an expression of type 'Texture1D', got 'Texture1D' Texture1D t1 = tex; - // expected an expression of type 'Texture2D', got 'Texture1D' +//CHECK: tests/diagnostics/mismatching-types.slang(76): error 30019: expected an expression of type 'Texture2D', got 'Texture1D' Texture2D t2 = tex; } \ No newline at end of file diff --git a/tests/diagnostics/variable-redeclaration.slang b/tests/diagnostics/variable-redeclaration.slang index bbd6a07c01..d2d9f90d70 100644 --- a/tests/diagnostics/variable-redeclaration.slang +++ b/tests/diagnostics/variable-redeclaration.slang @@ -1,6 +1,6 @@ // variable-redeclaration.slang -//DIAGNOSTIC_TEST:SIMPLE: +//TEST:SIMPLE(filecheck=CHECK): -target hlsl // This test confirms that the compiler produces @@ -52,3 +52,15 @@ int testParameterRedeclaration( { return size; } + +//CHECK: tests/diagnostics/variable-redeclaration.slang(14): error 30200: declaration of 'gA' conflicts with existing declaration +//CHECK: tests/diagnostics/variable-redeclaration.slang(12): note: see previous declaration of 'gA' +//CHECK: tests/diagnostics/variable-redeclaration.slang(44): error 30200: declaration of 'f' conflicts with existing declaration +//CHECK: tests/diagnostics/variable-redeclaration.slang(43): note: see previous declaration of 'f' +//CHECK: tests/diagnostics/variable-redeclaration.slang(51): error 30200: declaration of 'size' conflicts with existing declaration +//CHECK: tests/diagnostics/variable-redeclaration.slang(50): note: see previous declaration of 'size' +//CHECK: tests/diagnostics/variable-redeclaration.slang(21): error 30200: declaration of 'y' conflicts with existing declaration +//CHECK: tests/diagnostics/variable-redeclaration.slang(20): note: see previous declaration of 'y' +//CHECK: tests/diagnostics/variable-redeclaration.slang(53): error 39999: ambiguous reference to 'size' +//CHECK: tests/diagnostics/variable-redeclaration.slang(51): note 39999: candidate: float size +//CHECK: tests/diagnostics/variable-redeclaration.slang(50): note 39999: candidate: int size \ No newline at end of file diff --git a/tests/diagnostics/variable-redeclaration.slang.expected b/tests/diagnostics/variable-redeclaration.slang.expected deleted file mode 100644 index 944037b1cd..0000000000 --- a/tests/diagnostics/variable-redeclaration.slang.expected +++ /dev/null @@ -1,38 +0,0 @@ -result code = -1 -standard error = { -tests/diagnostics/variable-redeclaration.slang(14): error 30200: declaration of 'gA' conflicts with existing declaration -static Texture2D gA; - ^~ -tests/diagnostics/variable-redeclaration.slang(12): note: see previous declaration of 'gA' -static int gA; - ^~ -tests/diagnostics/variable-redeclaration.slang(44): error 30200: declaration of 'f' conflicts with existing declaration - float f; - ^ -tests/diagnostics/variable-redeclaration.slang(43): note: see previous declaration of 'f' - int f; - ^ -tests/diagnostics/variable-redeclaration.slang(51): error 30200: declaration of 'size' conflicts with existing declaration - float size) - ^~~~ -tests/diagnostics/variable-redeclaration.slang(50): note: see previous declaration of 'size' - int size, - ^~~~ -tests/diagnostics/variable-redeclaration.slang(21): error 30200: declaration of 'y' conflicts with existing declaration - int y = x; - ^ -tests/diagnostics/variable-redeclaration.slang(20): note: see previous declaration of 'y' - int y = x; - ^ -tests/diagnostics/variable-redeclaration.slang(53): error 39999: ambiguous reference to 'size' - return size; - ^~~~ -tests/diagnostics/variable-redeclaration.slang(51): note 39999: candidate: float size - float size) - ^~~~ -tests/diagnostics/variable-redeclaration.slang(50): note 39999: candidate: int size - int size, - ^~~~ -} -standard output = { -} From 04f7177e5ece46a3a2a5a66a45177e225c8f7fa4 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 16 Aug 2024 17:59:19 -0400 Subject: [PATCH 016/100] add missing include (clang/gcc) --- source/slang/slang-doc-ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/slang/slang-doc-ast.cpp b/source/slang/slang-doc-ast.cpp index 1bc33bf192..c252139d28 100644 --- a/source/slang/slang-doc-ast.cpp +++ b/source/slang/slang-doc-ast.cpp @@ -2,7 +2,7 @@ #include "slang-doc-ast.h" #include "../core/slang-string-util.h" - +#include "slang/slang-ast-support-types.h" //#include "slang-ast-builder.h" //#include "slang-ast-print.h" From 67c9d2919a091d04b7e13846a248c7cc357e2a94 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 19 Aug 2024 09:36:13 -0400 Subject: [PATCH 017/100] Clean up invalid tests, fix some bugs, add better use-site inference for ctor --- source/slang/diff.meta.slang | 1 + source/slang/hlsl.meta.slang | 4 +- source/slang/slang-ast-type.h | 5 + source/slang/slang-check-conversion.cpp | 14 +- source/slang/slang-check-decl.cpp | 135 ++++++++++---- source/slang/slang-check-impl.h | 5 +- source/slang/slang-check-overload.cpp | 172 ++++++++++++------ tests/bugs/c-style-cast-coerce.slang | 4 +- tests/bugs/c-style-cast-coerce.slang.expected | 8 - .../initializer-lists/readonly-member.slang | 22 +++ .../initializer-lists/torch-tensor.slang | 71 ++++++++ .../rasterization/mesh/hlsl-syntax.slang | 16 +- .../rasterization/mesh/passing-outputs.slang | 8 +- .../ray-tracing/trace-ray-inline.slang | 28 ++- 14 files changed, 373 insertions(+), 120 deletions(-) delete mode 100644 tests/bugs/c-style-cast-coerce.slang.expected create mode 100644 tests/language-feature/initializer-lists/readonly-member.slang create mode 100644 tests/language-feature/initializer-lists/torch-tensor.slang diff --git a/source/slang/diff.meta.slang b/source/slang/diff.meta.slang index a4c468ef7a..0c558362ac 100644 --- a/source/slang/diff.meta.slang +++ b/source/slang/diff.meta.slang @@ -1025,6 +1025,7 @@ struct DiffTensorView /// Represents the handle of a Torch tensor object. __generic __intrinsic_type($(kIROp_TorchTensorType)) +__magic_type(TorchTensorType) struct TorchTensor { __intrinsic_op($(kIROp_TorchTensorGetView)) diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 530a9a3617..c9d36715d5 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -15470,7 +15470,7 @@ struct RayDesc __target_intrinsic(hlsl, TMin) __target_intrinsic(cuda, TMin) - float TMin; + float TMin; __target_intrinsic(hlsl, Direction) __target_intrinsic(cuda, Direction) @@ -15478,7 +15478,7 @@ struct RayDesc __target_intrinsic(hlsl, TMax) __target_intrinsic(cuda, TMax) - float TMax; + float TMax; }; // 10.1.3 - Ray Acceleration Structure diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h index 3a13186969..2eb1da548b 100644 --- a/source/slang/slang-ast-type.h +++ b/source/slang/slang-ast-type.h @@ -512,6 +512,11 @@ class TensorViewType : public BuiltinType Type* getElementType(); }; +class TorchTensorType : public BuiltinType +{ + SLANG_AST_CLASS(TorchTensorType) +}; + // Base class for built in string types class StringTypeBase : public BuiltinType { diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 6c9da739fd..a65cbbc6d8 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -479,7 +479,10 @@ namespace Slang if (argCount == 0) { if (outToExpr) + { *outToExpr = constructDefaultInitExprForVar(this, (TypeExp)toType, nullptr); + (*outToExpr)->loc = fromInitializerListExpr->loc; + } return true; } @@ -552,19 +555,22 @@ namespace Slang // We want lookup to resolve our init function as a generic using Slang's // builtin 'lookup' logic. + // Note, we need to also ensure we can infer the generic based on the target type auto ctorToInvoke = m_astBuilder->create(); - ctorToInvoke->scope = this->getOuterScope(); + ctorToInvoke->scope = toStructDecl->ownedScope; ctorToInvoke->name = getName(String(toStructDecl->getName()->text)); - + ctorToInvoke->type = toType; Expr* callee = ctorToInvoke; InvokeExpr* constructorExpr = m_astBuilder->create(); constructorExpr->loc = fromInitializerListExpr->loc; - constructorExpr->functionExpr = callee; + constructorExpr->functionExpr = CheckTerm(callee); constructorExpr->arguments.addRange(coercedArgs); constructorExpr->type = toType; - *outToExpr = CheckExpr(constructorExpr); + //TODO: + + *outToExpr = CheckInvokeExprWithCheckedOperands(constructorExpr); } return true; } diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 44f90fa83b..36483e857c 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7682,6 +7682,55 @@ namespace Slang return ctor->containsOption(ConstructorTags::Synthesized) && ctor->getParameters().getCount() != 0 && !allParamHaveInitExpr(ctor); } + template + static bool containsTargetType(ASTBuilder* m_astBuilder, NodeBase* target) + { + if (!target) + return false; + + if (as(target)) + return true; + + if (auto aggTypeDecl = as(target)) + { + for (auto i : getMembersOfType(m_astBuilder, aggTypeDecl, MemberFilterStyle::Instance)) + if (containsTargetType(m_astBuilder, i.getDecl()->type)) + return true; + } + else if (auto genericDecl = as(target)) + { + for (auto i : genericDecl->getArgs()) + if (containsTargetType(m_astBuilder, as(i))) + return true; + return containsTargetType(m_astBuilder, genericDecl->getBase()); + } + else if (auto vectorExpr = as(target)) + { + return containsTargetType(m_astBuilder, vectorExpr->getElementType()); + } + else if (auto matrixExpr = as(target)) + { + return containsTargetType(m_astBuilder, matrixExpr->getElementType()); + } + else if (auto arrayExpr = as(target)) + { + return containsTargetType(m_astBuilder, arrayExpr->getElementType()); + } + else if (auto basicExpr = as(target)) + { + return containsTargetType(m_astBuilder, basicExpr->getDeclRef()); + } + else if (auto declRefType = as(target)) + { + return containsTargetType(m_astBuilder, declRefType->getDeclRef()); + } + else if (auto directDeclRef = as(target)) + { + return containsTargetType(m_astBuilder, directDeclRef->getDecl()); + } + return false; + } + void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl) { if (aggTypeDecl->hasTag(TypeTag::Incomplete) && aggTypeDecl->hasModifier()) @@ -7888,6 +7937,9 @@ namespace Slang thisExpr->type = ctor->returnType.type; auto paramCount = paramList.getCount(); + + // ensure synth'ed ctor has correct modifier to tag as a "CUDA host function" + bool foundCudaHostModifier = false; while (paramIndex < paramCount) { auto param = paramList[paramIndex]; @@ -7912,6 +7964,14 @@ namespace Slang } if (baseCtor) { + //Manage CUDA host modifier based on inheritance + if (baseCtor->findModifier()) + { + foundCudaHostModifier = true; + addModifier(ctor, m_astBuilder->create()); + } + // + auto baseCtorParamCount = baseCtor->getParameters().getCount(); // Now assign the found ctor and add it to our auto-synthisized ctor @@ -7957,15 +8017,26 @@ namespace Slang paramExpr->type = paramType; paramExpr->loc = param->loc; - // Skip static members + // Do not map a variable which is not visible + // Do not map a read-only variable for default-init VarDeclBase* member = members[memberIndex++].getDecl(); - while (getDeclVisibility(member) < ctorVisibility) + while (getDeclVisibility(member) < ctorVisibility + || !getTypeForDeclRef(m_astBuilder, member, member->loc).isLeftValue) { // Should note be possible to be out of range unless compiler generated a synth-ctor wrong. SLANG_ASSERT(memberIndex < members.getCount()); member = members[memberIndex++].getDecl(); } + //Manage CUDA host modifier based on inheritance + //containsType + if (!foundCudaHostModifier && containsTargetType(m_astBuilder, member->type.type)) + { + foundCudaHostModifier = true; + addModifier(ctor, m_astBuilder->create()); + } + // + MemberExpr* memberExpr = m_astBuilder->create(); memberExpr->baseExpression = thisExpr; memberExpr->declRef = member->getDefaultDeclRef(); @@ -10335,37 +10406,39 @@ namespace Slang // a (1:1 element) ctor for public members (public member-wise ctor) to synthesize. // This principal also applies for private members and internal/public member-wise ctor synthisis. DeclVisibility maxVisibilityToGenerateCtor = getDeclVisibility(structDecl); - for(auto m : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) + for(auto varDeclRef : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) { - if (auto varDeclRef = as(m)) - { - auto varDecl = varDeclRef.getDecl(); - ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); - auto declVisibility = getDeclVisibility(varDecl); + auto varDecl = varDeclRef.getDecl(); + ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); - switch (declVisibility) - { - case DeclVisibility::Private: - publicPrivateInternalCtorArgs.add(varDecl); - if(!varDecl->initExpr) - maxVisibilityToGenerateCtor = DeclVisibility::Private; - break; - case DeclVisibility::Internal: - publicPrivateInternalCtorArgs.add(varDecl); - publicInternalCtorArgs.add(varDecl); - if (!varDecl->initExpr) - maxVisibilityToGenerateCtor = DeclVisibility::Internal; - break; - case DeclVisibility::Public: - publicPrivateInternalCtorArgs.add(varDecl); - publicInternalCtorArgs.add(varDecl); - publicCtorArgs.add(varDecl); - break; - default: - // Unknown visibility - SLANG_ASSERT(false); - break; - } + // Do not map a read-only variable for default-init + if (!getTypeForDeclRef(m_astBuilder, varDeclRef, varDeclRef.getLoc()).isLeftValue) + continue; + + auto declVisibility = getDeclVisibility(varDecl); + + switch (declVisibility) + { + case DeclVisibility::Private: + publicPrivateInternalCtorArgs.add(varDecl); + if(!varDecl->initExpr) + maxVisibilityToGenerateCtor = DeclVisibility::Private; + break; + case DeclVisibility::Internal: + publicPrivateInternalCtorArgs.add(varDecl); + publicInternalCtorArgs.add(varDecl); + if (!varDecl->initExpr) + maxVisibilityToGenerateCtor = DeclVisibility::Internal; + break; + case DeclVisibility::Public: + publicPrivateInternalCtorArgs.add(varDecl); + publicInternalCtorArgs.add(varDecl); + publicCtorArgs.add(varDecl); + break; + default: + // Unknown visibility + SLANG_ASSERT(false); + break; } } if (maxVisibilityToGenerateCtor >= DeclVisibility::Public) diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index f82dd0136a..7da136c315 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -2758,6 +2758,8 @@ namespace Slang CASE(DerefExpr) CASE(MakeRefExpr) + CASE(MatrixSwizzleExpr) + CASE(SwizzleExpr) CASE(OverloadedExpr) CASE(OverloadedExpr2) CASE(AggTypeCtorExpr) @@ -2769,9 +2771,6 @@ namespace Slang CASE(PartiallyAppliedGenericExpr) CASE(PackExpr) #undef CASE - - Expr* visitSwizzleExpr(SwizzleExpr* expr) { return expr; } - Expr* visitMatrixSwizzleExpr(MatrixSwizzleExpr* expr) { return expr; } Expr* visitStaticMemberExpr(StaticMemberExpr* expr); diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 673891f72b..91109ab83d 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -1188,7 +1188,7 @@ namespace Slang // this kind of "is an override of ..." information on declarations // directly (it is only visible through the requirement witness // information for inheritance declarations). - + // auto leftDeclRefParent = left.declRef.getParent(); auto rightDeclRefParent = right.declRef.getParent(); bool leftIsInterfaceRequirement = isInterfaceRequirement(left.declRef.getDecl()); @@ -1776,7 +1776,16 @@ namespace Slang ConstraintSystem constraints; constraints.loc = context.loc; constraints.genericDecl = genericDeclRef.getDecl(); + + List membersToResolve; + for (auto i : constraints.genericDecl->members) + { + if (as(i)) + continue; + membersToResolve.add(i); + } auto innerDecl = genericDeclRef.getDecl()->inner; + // In order to perform matching between the types passed in at the // call site represented by `context` and the parameters of the // declaraiton being applied, we want to form a reference to @@ -1789,6 +1798,8 @@ namespace Slang if (as(genericDeclRef.getDecl()->inner)) { // We have a ctor. We need to get the underlying callable. + // We have a ctor, we can assume that the generic arg list is equal to our return type + // arg list auto functionVarExpr = as(context.originalExpr->functionExpr); if (auto genericFunctionDeclRef = as(functionVarExpr->declRef)) { @@ -1811,75 +1822,123 @@ namespace Slang } } - if (auto funcDeclRef = as(innerDecl)) + // TODO: Infer generics using return-type with parameter-list correctly through checking function body. + + // Infer generic based on return-type with ctor + // TODO: mix with deducing generics from parameter list, if we do this we will be able + // to use this logic for all ctor's. This addition would be required since otherwise + // a return-type which is type "U" may be more ambiguous than a parameter of type "int" + // and cause compile error. + if (as(innerDecl) + && as(innerDecl)->containsOption(ConstructorTags::Synthesized) + && context.originalExpr && context.originalExpr->type.type) { - List paramTypes; - if (!innerParameterTypes) + if (auto declRefType = as(context.originalExpr->type.type)) { - auto params = getParameters(m_astBuilder, funcDeclRef).toArray(); - for (auto param : params) + if (auto genericAppDeclRef = as(declRefType->getDeclRefBase())) { - paramTypes.add(getParamQualType(m_astBuilder, param)); - } - innerParameterTypes = ¶mTypes; - } + Index genericDeclArgIndex = 0; + auto genericDeclArgCount = membersToResolve.getCount(); + + Index genericAppDeclRefIndex = 0; + auto genericAppDeclRefArgCount = genericAppDeclRef->getArgCount(); + + while (genericAppDeclRefArgCount > genericAppDeclRefIndex + && genericDeclArgCount > genericDeclArgIndex) + { + auto genericAppDeclRefArg = genericAppDeclRef->getArg(genericAppDeclRefIndex); + if (as(genericAppDeclRefArg)) + { + genericAppDeclRefIndex++; + continue; + } - ShortList matchedArgs; + auto genericDeclArg = membersToResolve[genericDeclArgIndex]; - // We now try to match arguments to parameters. - // - // Note that if there are *too few* arguments, we might still have - // a match, because the other arguments might have default values - // that can be used. - // - if (!context.matchArgumentsToParams(this, *innerParameterTypes, true, matchedArgs)) - { - return DeclRef(); + Constraint constraint; + constraint.decl = genericDeclArg; + constraint.val = genericAppDeclRefArg; + constraints.constraints.add(constraint); + + genericDeclArgIndex++; + genericAppDeclRefIndex++; + } + } } + } - // Perform type unification between arguments and parameters, so - // we can populate the resolve system with inital constraints. - // - for (Index aa = 0; aa < matchedArgs.getCount(); ++aa) + if(constraints.constraints.getCount() == 0) + { + // Infer generics using parameters to function + if (auto funcDeclRef = as(innerDecl)) { - // The question here is whether failure to "unify" an argument - // and parameter should lead to immediate failure. - // - // The case that is interesting is if we want to unify, say: - // `vector` and `vector` - // - // It is clear that we should solve with `N = 3`, and then - // a later step may find that the resulting types aren't - // actually a match. + List paramTypes; + if (!innerParameterTypes) + { + auto params = getParameters(m_astBuilder, funcDeclRef).toArray(); + for (auto param : params) + { + paramTypes.add(getParamQualType(m_astBuilder, param)); + } + innerParameterTypes = ¶mTypes; + } + + ShortList matchedArgs; + + // We now try to match arguments to parameters. // - // A more refined approach to "unification" could of course - // see that `int` can convert to `float` and use that fact. - // (and indeed we already use something like this to unify - // `float` and `vector`) + // Note that if there are *too few* arguments, we might still have + // a match, because the other arguments might have default values + // that can be used. // - // So the question is then whether a mismatch during the - // unification step should be taken as an immediate failure... - auto argType = matchedArgs[aa].argType; - auto paramType = (*innerParameterTypes)[aa]; - auto canUnify = TryUnifyTypes( - constraints, - ValUnificationContext(), - QualType(argType, paramType.isLeftValue), - paramType); - - // It is an error if we can't unify the argument with a type pack parameter. - if (!canUnify && isTypePack(paramType)) + if (!context.matchArgumentsToParams(this, *innerParameterTypes, true, matchedArgs)) { return DeclRef(); } + + // Perform type unification between arguments and parameters, so + // we can populate the resolve system with inital constraints. + // + for (Index aa = 0; aa < matchedArgs.getCount(); ++aa) + { + // The question here is whether failure to "unify" an argument + // and parameter should lead to immediate failure. + // + // The case that is interesting is if we want to unify, say: + // `vector` and `vector` + // + // It is clear that we should solve with `N = 3`, and then + // a later step may find that the resulting types aren't + // actually a match. + // + // A more refined approach to "unification" could of course + // see that `int` can convert to `float` and use that fact. + // (and indeed we already use something like this to unify + // `float` and `vector`) + // + // So the question is then whether a mismatch during the + // unification step should be taken as an immediate failure... + auto argType = matchedArgs[aa].argType; + auto paramType = (*innerParameterTypes)[aa]; + auto canUnify = TryUnifyTypes( + constraints, + ValUnificationContext(), + QualType(argType, paramType.isLeftValue), + paramType); + + // It is an error if we can't unify the argument with a type pack parameter. + if (!canUnify && isTypePack(paramType)) + { + return DeclRef(); + } + } + } + else + { + // TODO(tfoley): any other cases needed here? + return DeclRef(); } } - else - { - // TODO(tfoley): any other cases needed here? - return DeclRef(); - } - // Once we have added all the appropriate constraints to the system, we // will try to solve for a set of arguments to the generic that satisfy // those constraints. @@ -1891,8 +1950,7 @@ namespace Slang // TODO(tfoley): We probably need to pass along the explicit arguments here, // so that the solver knows to accept those arguments as-is. // - return trySolveConstraintSystem( - &constraints, genericDeclRef, knownGenericArgs, outBaseCost); + return trySolveConstraintSystem(&constraints, genericDeclRef, knownGenericArgs, outBaseCost); } void SemanticsVisitor::AddTypeOverloadCandidates( diff --git a/tests/bugs/c-style-cast-coerce.slang b/tests/bugs/c-style-cast-coerce.slang index e01903e2cc..b123638415 100644 --- a/tests/bugs/c-style-cast-coerce.slang +++ b/tests/bugs/c-style-cast-coerce.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//TEST:SIMPLE(filecheck=CHECK): -target hlsl // It used to be the case that coercions of already-coerced initializer lists // didn't take into account the more specific type. One way of triggering this @@ -6,6 +6,8 @@ // syntax which creates the equivalent of `{} : S`. In the example below this // then proceeds to be coerced to type T. +//CHECK: c-style-cast-coerce.slang(17): error 30019: expected an expression of type 'T', got 'S' + struct S {}; struct T {}; diff --git a/tests/bugs/c-style-cast-coerce.slang.expected b/tests/bugs/c-style-cast-coerce.slang.expected deleted file mode 100644 index a09c6842fe..0000000000 --- a/tests/bugs/c-style-cast-coerce.slang.expected +++ /dev/null @@ -1,8 +0,0 @@ -result code = -1 -standard error = { -tests/bugs/c-style-cast-coerce.slang(15): error 30019: expected an expression of type 'T', got 'S' - T t = (S)0; - ^ -} -standard output = { -} diff --git a/tests/language-feature/initializer-lists/readonly-member.slang b/tests/language-feature/initializer-lists/readonly-member.slang new file mode 100644 index 0000000000..46dabf48e8 --- /dev/null +++ b/tests/language-feature/initializer-lists/readonly-member.slang @@ -0,0 +1,22 @@ +//TEST:SIMPLE(filecheck=PASS): -target hlsl -allow-glsl -entry computeMain -stage compute + +struct Test +{ + readonly uint a; + writeonly uint b; +}; + +//PASS: computeMain +//PASS-NOT + +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test test = {2}; + + outputBuffer[0] = true + && test.b == 2; + ; +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/torch-tensor.slang b/tests/language-feature/initializer-lists/torch-tensor.slang new file mode 100644 index 0000000000..f5ea1ac493 --- /dev/null +++ b/tests/language-feature/initializer-lists/torch-tensor.slang @@ -0,0 +1,71 @@ +//TEST:SIMPLE(filecheck=CUDA): -target cuda -line-directive-mode none +//TEST:SIMPLE(filecheck=TORCH): -target torch -line-directive-mode none + + +struct MySubType +{ + TorchTensor array[2]; +} + +struct MyType +{ + float2 v; + MySubType sub[2]; +} + +struct MyType2 +{ + float2 v; + TorchTensor tensor; +} + +struct ReturnType +{ + MyType t1; + MyType2 t2; +} + +struct MyInput +{ + TorchTensor inValues; + float normalVal; +} + +// CUDA: __global__ void myKernel(TensorView inValues_[[#]], TensorView outValues_[[#]]) +[CudaKernel] +void myKernel(TensorView inValues, TensorView outValues) +{ + if (cudaThreadIdx().x > 0) + return; + outValues.store(cudaThreadIdx().x, sin(inValues.load(cudaThreadIdx().x))); +} + +// TORCH: {{^SLANG_PRELUDE_EXPORT$}} +// TORCH-NEXT: void myKernel(TensorView {{[[:alnum:]_]+}}, TensorView {{[[:alnum:]_]+}}); +// +// TORCH: {{^SLANG_PRELUDE_EXPORT$}} +// TORCH-NEXT: runCompute(std::tuple input_[[#]]) +[TorchEntryPoint] +export __extern_cpp ReturnType runCompute(MyInput input) +{ + MyType rs; + var outValues = TorchTensor.alloc(1); + let inValues = input.inValues; + + __dispatch_kernel(myKernel, uint3(1, 1, 1), uint3(32, 1, 1))(inValues, outValues); + + rs.v = float2(1.0, 2.0); + rs.sub[0].array[0] = outValues; + rs.sub[0].array[1] = inValues; + + rs.sub[1].array[0] = inValues; + rs.sub[1].array[1] = outValues; + + MyType2 rs2; + rs2.tensor = outValues; + + ReturnType returnVal; + returnVal.t1 = rs; + returnVal.t2 = rs2; + return returnVal; +} diff --git a/tests/pipeline/rasterization/mesh/hlsl-syntax.slang b/tests/pipeline/rasterization/mesh/hlsl-syntax.slang index 76ac3a598e..9e4614660e 100644 --- a/tests/pipeline/rasterization/mesh/hlsl-syntax.slang +++ b/tests/pipeline/rasterization/mesh/hlsl-syntax.slang @@ -2,7 +2,21 @@ // Test that we can ingest hlsl mesh output syntax -//TEST:CROSS_COMPILE:-target spirv -profile sm_6_5 -entry main -stage mesh +//TEST:SIMPLE(filecheck=CHECK):-target spirv -profile sm_6_5 -entry main -stage mesh + +//CHECK: OpCapability MeshShadingEXT +//CHECK: OpExtension "SPV_EXT_mesh_shader" +//CHECK-DAG: OpEntryPoint MeshEXT +//CHECK-DAG: OpExecutionMode %{{.*}} OutputPrimitivesEXT 1 +//CHECK-DAG: OpExecutionMode %{{.*}} OutputTrianglesEXT + +//CHECK: OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex +//CHECK-NOT: OpDecorate %gl_PrimitiveTriangleIndicesEXT BuiltIn PrimitiveTriangleIndicesEXT + +//CHECK: %gl_LocalInvocationIndex = OpVariable +//CHECK-NOT: %gl_PrimitiveTriangleIndicesEXT = OpVariable + +//CHECK: OpSetMeshOutputsEXT %uint_3 %uint_1 const static float2 positions[3] = { float2(0.0, -0.5), diff --git a/tests/pipeline/rasterization/mesh/passing-outputs.slang b/tests/pipeline/rasterization/mesh/passing-outputs.slang index 3fd6fc4a0d..80595c4564 100644 --- a/tests/pipeline/rasterization/mesh/passing-outputs.slang +++ b/tests/pipeline/rasterization/mesh/passing-outputs.slang @@ -2,7 +2,7 @@ // This tests that writing to individual components of the output struct works -//TEST:SIMPLE(filecheck=SPIRV): -target spirv-assembly -entry main -stage mesh -profile glsl_450+spirv_1_4 +//TEST:SIMPLE(filecheck=SPIRV): -target spirv-assembly -entry main -stage mesh -profile glsl_450+GL_EXT_mesh_shader // DXC is stricter than we are about passing references to individual mesh shader outputs // We could get around this by doing what we do for GLSL, i.e. use a temporary @@ -30,17 +30,17 @@ struct Vertex void everything(OutputVertices vs) { - vs[0] = {float4(0), float3(1)}; + vs[0] = { float4(0), float3(1), {} }; } void just_one(out Vertex v) { - v = {float4(0), float3(1)}; + v = { float4(0), float3(1), {} }; } void just_two(out Vertex v, out Vertex w) { - v = {float4(0), float3(1)}; + v = { float4(0), float3(1), {} }; w = v; } diff --git a/tests/pipeline/ray-tracing/trace-ray-inline.slang b/tests/pipeline/ray-tracing/trace-ray-inline.slang index b8688c2f5c..09b470a91b 100644 --- a/tests/pipeline/ray-tracing/trace-ray-inline.slang +++ b/tests/pipeline/ray-tracing/trace-ray-inline.slang @@ -1,14 +1,24 @@ // trace-ray-inline.slang -//TEST:CROSS_COMPILE:-target dxil-asm -stage compute -profile sm_6_5 -entry main -line-directive-mode none -//TEST:SIMPLE(filecheck=CHECK):-target spirv-asm -stage compute -profile glsl_460+GL_EXT_ray_query -entry main -line-directive-mode none - -// CHECK: OpCapability RayQueryKHR -// CHECK: OpExtension "SPV_KHR_ray_query" -// CHECK: OpRayQueryInitializeKHR -// CHECK: OpRayQueryProceedKHR -// CHECK: OpRayQueryGetIntersectionTypeKHR -// CHECK: OpRayQueryConfirmIntersectionKHR +//TEST:SIMPLE(filecheck=HLSL):-target hlsl -stage compute -profile sm_6_5 -entry main +//TEST:SIMPLE(filecheck=DXIL):-target dxil -stage compute -profile sm_6_5 -entry main +//TEST:SIMPLE(filecheck=SPV):-target spirv-asm -stage compute -profile glsl_460+GL_EXT_ray_query -entry main + +// HLSL: {{.*}}.TraceRayInline +// HLSL: {{.*}}.Proceed +// HLSL: {{.*}}.CandidateType +// HLSL: {{.*}}.CommitProceduralPrimitiveHit +// HLSL: {{.*}}.CommitNonOpaqueTriangleHit + +/// ensure the compiled HLSL is valid +// DXIL: @main + +// SPV: OpCapability RayQueryKHR +// SPV: OpExtension "SPV_KHR_ray_query" +// SPV: OpRayQueryInitializeKHR +// SPV: OpRayQueryProceedKHR +// SPV: OpRayQueryGetIntersectionTypeKHR +// SPV: OpRayQueryConfirmIntersectionKHR // The goal of this shader is to use all the main pieces // of functionality in DXR 1.1's `TraceRayInline` feature, From 7476962274ed641069eb2ae8b1b6b384686468e9 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 19 Aug 2024 09:50:06 -0400 Subject: [PATCH 018/100] clang/gcc compiler warning --- source/slang/slang-doc-ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/slang/slang-doc-ast.cpp b/source/slang/slang-doc-ast.cpp index c252139d28..59c50b69f4 100644 --- a/source/slang/slang-doc-ast.cpp +++ b/source/slang/slang-doc-ast.cpp @@ -49,7 +49,7 @@ namespace Slang { bool doWeDocDecl(Decl* decl) { - return !getText(decl->getName()).startsWith("$__syn") && !decl->findModifier(); + return !getText(decl->getName()).startsWith("$__syn") && !decl->hasModifier(); } static void _addDeclRec(Decl* decl, List& outDecls) From 78feed69a34803451c38e092afeef4515c86fb5c Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:00:22 -0400 Subject: [PATCH 019/100] cyclic type solution --- source/slang/slang-check-decl.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 36483e857c..a24312d5cf 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7683,7 +7683,7 @@ namespace Slang } template - static bool containsTargetType(ASTBuilder* m_astBuilder, NodeBase* target) + bool _containsTargetType(ASTBuilder* m_astBuilder, NodeBase* target, HashSet& visitedNodes) { if (!target) return false; @@ -7691,46 +7691,57 @@ namespace Slang if (as(target)) return true; + if (visitedNodes.contains(target)) + return false; + visitedNodes.add(target); + if (auto aggTypeDecl = as(target)) { for (auto i : getMembersOfType(m_astBuilder, aggTypeDecl, MemberFilterStyle::Instance)) - if (containsTargetType(m_astBuilder, i.getDecl()->type)) + if (_containsTargetType(m_astBuilder, i.getDecl()->type, visitedNodes)) return true; } else if (auto genericDecl = as(target)) { for (auto i : genericDecl->getArgs()) - if (containsTargetType(m_astBuilder, as(i))) + if (_containsTargetType(m_astBuilder, as(i), visitedNodes)) return true; - return containsTargetType(m_astBuilder, genericDecl->getBase()); + return _containsTargetType(m_astBuilder, genericDecl->getBase(), visitedNodes); } else if (auto vectorExpr = as(target)) { - return containsTargetType(m_astBuilder, vectorExpr->getElementType()); + return _containsTargetType(m_astBuilder, vectorExpr->getElementType(), visitedNodes); } else if (auto matrixExpr = as(target)) { - return containsTargetType(m_astBuilder, matrixExpr->getElementType()); + return _containsTargetType(m_astBuilder, matrixExpr->getElementType(), visitedNodes); } else if (auto arrayExpr = as(target)) { - return containsTargetType(m_astBuilder, arrayExpr->getElementType()); + return _containsTargetType(m_astBuilder, arrayExpr->getElementType(), visitedNodes); } else if (auto basicExpr = as(target)) { - return containsTargetType(m_astBuilder, basicExpr->getDeclRef()); + return _containsTargetType(m_astBuilder, basicExpr->getDeclRef(), visitedNodes); } else if (auto declRefType = as(target)) { - return containsTargetType(m_astBuilder, declRefType->getDeclRef()); + return _containsTargetType(m_astBuilder, declRefType->getDeclRef(), visitedNodes); } else if (auto directDeclRef = as(target)) { - return containsTargetType(m_astBuilder, directDeclRef->getDecl()); + return _containsTargetType(m_astBuilder, directDeclRef->getDecl(), visitedNodes); } return false; } + template + bool containsTargetType(ASTBuilder* m_astBuilder, NodeBase* target) + { + HashSet visitedNodes; + return _containsTargetType(m_astBuilder, target, visitedNodes); + } + void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl) { if (aggTypeDecl->hasTag(TypeTag::Incomplete) && aggTypeDecl->hasModifier()) From 98cd3b337cde88d3bd547a4f47781e7837a4b7d9 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:03:58 -0400 Subject: [PATCH 020/100] include header that defines another function (whom is in a header). --- source/slang/slang-doc-ast.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/slang/slang-doc-ast.h b/source/slang/slang-doc-ast.h index 34bba8b7b8..f637f62161 100644 --- a/source/slang/slang-doc-ast.h +++ b/source/slang/slang-doc-ast.h @@ -8,6 +8,8 @@ #include "slang-ast-all.h" +#include "slang-syntax.h" + namespace Slang { /* Holds the documentation markup that is associated with each node (typically a decl) from a module */ From a788a5313f516eaf0393d192588d484ccf5830e2 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:18:17 -0400 Subject: [PATCH 021/100] fix bit fields --- source/slang/slang-check-decl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index a24312d5cf..e8a0f85bb2 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -8030,9 +8030,12 @@ namespace Slang // Do not map a variable which is not visible // Do not map a read-only variable for default-init + // Do not map compiler generated 'internal processing' variable VarDeclBase* member = members[memberIndex++].getDecl(); while (getDeclVisibility(member) < ctorVisibility - || !getTypeForDeclRef(m_astBuilder, member, member->loc).isLeftValue) + || !getTypeForDeclRef(m_astBuilder, member, member->loc).isLeftValue + || member->getName() && member->getName()->text[0] == '$' + ) { // Should note be possible to be out of range unless compiler generated a synth-ctor wrong. SLANG_ASSERT(memberIndex < members.getCount()); From ff905aeeff478cb3da7328695f4e0943ecae6f06 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 19 Aug 2024 17:15:43 -0400 Subject: [PATCH 022/100] fix no_diff and trySynthesizeDifferentialAssociatedTypeRequirementWitness bug Adding 2 things: 1. add no_diff to synth'ed ctor if param is no_diff 2. Fix bug where DifferentialType 'ownedScope' is not setup to track the associated contained (causes 'ThisExpr' to resolve incorrectly) --- source/slang/slang-ast-synthesis.h | 1 + source/slang/slang-check-decl.cpp | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/source/slang/slang-ast-synthesis.h b/source/slang/slang-ast-synthesis.h index e595afac12..0726360d3f 100644 --- a/source/slang/slang-ast-synthesis.h +++ b/source/slang/slang-ast-synthesis.h @@ -52,6 +52,7 @@ class ASTSynthesizer auto parentScope = getScope(decl); decl->ownedScope = m_builder->create(); decl->ownedScope->parent = parentScope; + decl->ownedScope->containerDecl = decl; pushContainerScope(decl); } diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index e8a0f85bb2..e26d6a76c8 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1854,6 +1854,9 @@ namespace Slang param->parentDecl = ctor; param->loc = ctor->loc; ctor->members.add(param); + + if (arg->hasModifier()) + addModifier(param, m_astBuilder->create()); } addVisibilityModifier(m_astBuilder, ctor, visibility); @@ -1925,6 +1928,8 @@ namespace Slang varDecl->initExpr = constructDefaultInitExprForVar(this, varDecl->type, varDecl); } + auto type = varDecl->getType(); + if (auto initExpr = varDecl->initExpr) { // Disable the short-circuiting for static const variable init expression @@ -1950,6 +1955,9 @@ namespace Slang varDecl->setCheckState(DeclCheckState::DefinitionChecked); _validateCircularVarDefinition(varDecl); } + // all structDecl's need to be set to a default value (else it is a compile error for HLSL) + else if (as(type)) + varDecl->initExpr = constructDefaultInitExprForVar(this, varDecl->type, varDecl); else { // If a variable doesn't have an explicit initial-value @@ -1972,12 +1980,12 @@ namespace Slang // and filtering them to ones that are applicable // to our "call site" with zero arguments. // + OverloadResolveContext overloadContext; overloadContext.loc = varDecl->nameAndLoc.loc; overloadContext.mode = OverloadResolveContext::Mode::JustTrying; overloadContext.sourceScope = m_outerScope; - auto type = varDecl->getType(); ImplicitCastMethodKey key = ImplicitCastMethodKey(QualType(), type, nullptr); auto ctorMethod = getShared()->tryGetImplicitCastMethod(key); if (ctorMethod) From 89e13395e52abb477751b29b11df617589c6e7e6 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 19 Aug 2024 20:52:03 -0400 Subject: [PATCH 023/100] Fix how auto-diff code is auto-generated by synthed ctor's member-wise synth'ed ctor's (to match how they worked when used in an init-list) check for differentiability of a member and per-member assigns no_diff appropriately. --- source/slang/slang-check-decl.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index e26d6a76c8..6144bf89b3 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1854,14 +1854,9 @@ namespace Slang param->parentDecl = ctor; param->loc = ctor->loc; ctor->members.add(param); - - if (arg->hasModifier()) - addModifier(param, m_astBuilder->create()); } - addVisibilityModifier(m_astBuilder, ctor, visibility); - addModifier(ctor, m_astBuilder->create()); - + addModifier(ctor, m_astBuilder->create()); decl->addMember(ctor); return ctor; } @@ -7934,6 +7929,9 @@ namespace Slang baseTypeCtorList = _getCtorList(m_astBuilder, this, baseStructRef.getDecl(), nullptr); } + if (structDecl->getName() && structDecl->getName()->text.equals("RayDesc")) + __debugbreak(); + // Insert parameters as values for member-wise init expression. for (auto& ctorInfo : structDeclInfo.ctorInfoList) { @@ -7983,13 +7981,12 @@ namespace Slang } if (baseCtor) { - //Manage CUDA host modifier based on inheritance + // Manage CUDA host modifier based on inheritance if (baseCtor->findModifier()) { foundCudaHostModifier = true; addModifier(ctor, m_astBuilder->create()); } - // auto baseCtorParamCount = baseCtor->getParameters().getCount(); @@ -8050,6 +8047,12 @@ namespace Slang member = members[memberIndex++].getDecl(); } + // Check for differentiability, if we cannot diff this member attach a no_diff attribute. + if (( !this->isTypeDifferentiable(member->type) || !member->hasModifier()) && !param->hasModifier()) + addModifier(param, m_astBuilder->create()); + + + //Manage CUDA host modifier based on inheritance //containsType if (!foundCudaHostModifier && containsTargetType(m_astBuilder, member->type.type)) From 4aced6e0173ade0246a05071018670c39c77d453 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 19 Aug 2024 21:00:04 -0400 Subject: [PATCH 024/100] remove debug code --- source/slang/slang-check-decl.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 6144bf89b3..8612fc3b29 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7929,9 +7929,6 @@ namespace Slang baseTypeCtorList = _getCtorList(m_astBuilder, this, baseStructRef.getDecl(), nullptr); } - if (structDecl->getName() && structDecl->getName()->text.equals("RayDesc")) - __debugbreak(); - // Insert parameters as values for member-wise init expression. for (auto& ctorInfo : structDeclInfo.ctorInfoList) { From 8771a3bbb11d80e9edf8d3c77e477eaeec4e6ba0 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 19 Aug 2024 23:22:35 -0400 Subject: [PATCH 025/100] Expand on automatic auto-diff modifier resolution needed to add additional inheritance-decl 'ensureDecl' to ensure we have derivative member modifiers setup correctly for correct derivative modifier annotation. --- source/slang/slang-check-decl.cpp | 98 ++++++++++++++++--------------- 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 8612fc3b29..62106664dc 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7758,29 +7758,35 @@ namespace Slang struct DeclAndCtorInfo { - StructDecl* parent = nullptr; - ConstructorDecl* defaultCtor = nullptr; - + AggTypeDecl* m_parent; + InheritanceDecl* m_inheritanceDecl; + ConstructorDecl* m_defaultCtor = nullptr; + struct CtorAndInsertOffset { - ConstructorDecl* ctor; - Index insertOffset; + ConstructorDecl* m_ctor; + Index m_insertOffset; }; - List ctorInfoList; + List m_ctorInfoList; DeclAndCtorInfo() { } - DeclAndCtorInfo(ASTBuilder* m_astBuilder, SemanticsVisitor* visitor, StructDecl* parent, const bool getOnlyDefault) + DeclAndCtorInfo(ASTBuilder* m_astBuilder, SemanticsVisitor* visitor, AggTypeDecl* parent, InheritanceDecl* inheritanceDecl, const bool getOnlyDefault) : m_parent(parent), m_inheritanceDecl(inheritanceDecl) { + // only get ctor info from structDecl + StructDecl* structDecl = as(parent); + if (!structDecl) + return; + if (getOnlyDefault) - defaultCtor = _getDefaultCtor(parent); + m_defaultCtor = _getDefaultCtor(structDecl); else { - auto ctorList = _getCtorList(m_astBuilder, visitor, parent, &defaultCtor); - ctorInfoList.reserve(ctorList.getCount()); + auto ctorList = _getCtorList(m_astBuilder, visitor, structDecl, &m_defaultCtor); + m_ctorInfoList.reserve(ctorList.getCount()); for(auto i : ctorList) - ctorInfoList.add({i, 0}); + m_ctorInfoList.add({i, 0}); } } }; @@ -7791,12 +7797,12 @@ namespace Slang auto declRefType = as(inheritanceMember->base.type); if (!declRefType) continue; - auto structOfInheritance = as(declRefType->getDeclRef().getDecl()); + auto structOfInheritance = as(declRefType->getDeclRef().getDecl()); if (!structOfInheritance) continue; - inheritanceDefaultCtorList.add(DeclAndCtorInfo(m_astBuilder, this, structOfInheritance, true)); + inheritanceDefaultCtorList.add(DeclAndCtorInfo(m_astBuilder, this, structOfInheritance, inheritanceMember, false)); } - DeclAndCtorInfo structDeclInfo = DeclAndCtorInfo(m_astBuilder, this, structDecl, false); + DeclAndCtorInfo structDeclInfo = DeclAndCtorInfo(m_astBuilder, this, structDecl, nullptr, false); // ensure all varDecl members are processed up to SemanticsBodyVisitor so we can be sure that if init expressions // of members are to be synthisised, they are. @@ -7816,9 +7822,9 @@ namespace Slang Dictionary cachedDeclToCheckedVar; // Insert 'this->base->__init()' into 'this->__init()'. - for (auto& ctorInfo : structDeclInfo.ctorInfoList) + for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { - auto ctor = ctorInfo.ctor; + auto ctor = ctorInfo.m_ctor; // Synthesized constructors should not inject a defaultCtor of base-struct-type // unless ctor has 0 parameters. This is to allow a ctor which desires to be @@ -7830,14 +7836,14 @@ namespace Slang seqStmtChild->stmts.reserve(inheritanceDefaultCtorList.getCount()); for (auto& declInfo : inheritanceDefaultCtorList) { - if (!declInfo.defaultCtor) + if (!declInfo.m_defaultCtor) continue; auto ctorToInvoke = m_astBuilder->create(); - ctorToInvoke->declRef = declInfo.defaultCtor->getDefaultDeclRef(); - ctorToInvoke->name = declInfo.defaultCtor->getName(); - ctorToInvoke->loc = declInfo.defaultCtor->loc; - ctorToInvoke->type = structDeclInfo.defaultCtor->returnType.type; + ctorToInvoke->declRef = declInfo.m_defaultCtor->getDefaultDeclRef(); + ctorToInvoke->name = declInfo.m_defaultCtor->getName(); + ctorToInvoke->loc = declInfo.m_defaultCtor->loc; + ctorToInvoke->type = structDeclInfo.m_defaultCtor->returnType.type; auto invoke = m_astBuilder->create(); invoke->functionExpr = ctorToInvoke; @@ -7848,11 +7854,11 @@ namespace Slang // A base may not have any value, if this is the case do not insert a `__init()` // since coercing is impossible. - if (!canCoerce(declInfo.defaultCtor->returnType.type, ctor->returnType.type, thisExpr)) + if (!canCoerce(declInfo.m_defaultCtor->returnType.type, ctor->returnType.type, thisExpr)) continue; auto assign = m_astBuilder->create(); - assign->left = coerce(CoercionSite::Initializer, declInfo.defaultCtor->returnType.type, thisExpr); + assign->left = coerce(CoercionSite::Initializer, declInfo.m_defaultCtor->returnType.type, thisExpr); assign->right = invoke; auto stmt = m_astBuilder->create(); stmt->expression = assign; @@ -7865,13 +7871,13 @@ namespace Slang continue; auto seqStmt = _ensureCtorBodyIsSeqStmt(m_astBuilder, ctor); - seqStmt->stmts.insert(ctorInfo.insertOffset++, seqStmtChild); + seqStmt->stmts.insert(ctorInfo.m_insertOffset++, seqStmtChild); } // Assign member variable init expressions - for (auto& ctorInfo : structDeclInfo.ctorInfoList) + for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { - auto ctor = ctorInfo.ctor; + auto ctor = ctorInfo.m_ctor; ThisExpr* thisExpr = m_astBuilder->create(); thisExpr->scope = ctor->ownedScope; thisExpr->type = ctor->returnType.type; @@ -7918,21 +7924,23 @@ namespace Slang continue; auto seqStmt = _ensureCtorBodyIsSeqStmt(m_astBuilder, ctor); - seqStmt->stmts.insert(ctorInfo.insertOffset++, seqStmtChild); + seqStmt->stmts.insert(ctorInfo.m_insertOffset++, seqStmtChild); } + // Note: we assume only 1 inheritance decl currently. // Pre-calculate if we have a base-type and its associated ctor-list - auto baseStructRef = findBaseStructDeclRef(m_astBuilder, structDecl); - List baseTypeCtorList; - if (baseStructRef) + // We also must ensure inheritance-decl is checked, else we may not have up-to-date 'DerivativeMemberAttribute' modifiers + DeclAndCtorInfo* baseCtorInfo = nullptr; + for(auto i : inheritanceDefaultCtorList) { - baseTypeCtorList = _getCtorList(m_astBuilder, this, baseStructRef.getDecl(), nullptr); + ensureDecl(i.m_inheritanceDecl, DeclCheckState::DefinitionChecked); + baseCtorInfo = &i; } // Insert parameters as values for member-wise init expression. - for (auto& ctorInfo : structDeclInfo.ctorInfoList) + for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { - auto ctor = ctorInfo.ctor; + auto ctor = ctorInfo.m_ctor; if(!_doesCtorExpectInitializerListUsage(ctor)) continue; auto ctorVisibility = getDeclVisibility(ctor); @@ -7959,20 +7967,20 @@ namespace Slang auto param = paramList[paramIndex]; // If we have a base type, the first arg is a 'base->__init(...)'. We need to find this 'base->__init(...)' // and assign the parameters needed to call '__init(...)' - if (paramIndex == 0 && baseTypeCtorList.getCount() > 0) + if (paramIndex == 0 && baseCtorInfo && baseCtorInfo->m_ctorInfoList.getCount() > 0) { - auto baseStruct = baseStructRef.getDecl(); + auto baseStruct = baseCtorInfo->m_parent; // First find a member-wise 'base->__init()' which maps to this current ctor being filled ConstructorDecl* baseCtor = nullptr; ConstructorTags memberwiseCtorToCall = ConstructorTags::MemberwiseCtorForPublicVisibility; if (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) memberwiseCtorToCall = ConstructorTags::MemberwiseCtorForInternalVisibility; - for (auto i : baseTypeCtorList) + for (auto& i : baseCtorInfo->m_ctorInfoList) { - if (i->containsOption(memberwiseCtorToCall)) + if (i.m_ctor->containsOption(memberwiseCtorToCall)) { - baseCtor = i; + baseCtor = i.m_ctor; break; } } @@ -8048,8 +8056,6 @@ namespace Slang if (( !this->isTypeDifferentiable(member->type) || !member->hasModifier()) && !param->hasModifier()) addModifier(param, m_astBuilder->create()); - - //Manage CUDA host modifier based on inheritance //containsType if (!foundCudaHostModifier && containsTargetType(m_astBuilder, member->type.type)) @@ -8078,24 +8084,24 @@ namespace Slang seqStmtChild->stmts.add(stmt); } - seqStmt->stmts.insert(ctorInfo.insertOffset++, seqStmtChild); + seqStmt->stmts.insert(ctorInfo.m_insertOffset++, seqStmtChild); } // Compiler generated ctor may be destroyed - if(structDeclInfo.defaultCtor - && structDeclInfo.defaultCtor->containsOption(ConstructorTags::Synthesized)) + if(structDeclInfo.m_defaultCtor + && structDeclInfo.m_defaultCtor->containsOption(ConstructorTags::Synthesized)) { bool destroy = false; - if (!structDeclInfo.defaultCtor->body) + if (!structDeclInfo.m_defaultCtor->body) destroy = true; - else if (auto block = as(structDeclInfo.defaultCtor->body)) + else if (auto block = as(structDeclInfo.m_defaultCtor->body)) { if (as(block->body)->stmts.getCount() == 0) destroy = true; } if (destroy) { - structDecl->members.remove(structDeclInfo.defaultCtor); + structDecl->members.remove(structDeclInfo.m_defaultCtor); structDecl->invalidateMemberDictionary(); structDecl->buildMemberDictionary(); } From 26908f5755c31956e8f3ba68e7517dff1e28325d Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 20 Aug 2024 00:27:23 -0400 Subject: [PATCH 026/100] fix bug related to inheritance walking introduced --- source/slang/slang-check-decl.cpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 62106664dc..3cb0e250b4 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7791,16 +7791,16 @@ namespace Slang } }; - List inheritanceDefaultCtorList{}; + List inheritanceInfoList{}; for (auto inheritanceMember : structDecl->getMembersOfType()) { auto declRefType = as(inheritanceMember->base.type); if (!declRefType) continue; - auto structOfInheritance = as(declRefType->getDeclRef().getDecl()); - if (!structOfInheritance) + auto typeOfInheritance = as(declRefType->getDeclRef().getDecl()); + if (!typeOfInheritance) continue; - inheritanceDefaultCtorList.add(DeclAndCtorInfo(m_astBuilder, this, structOfInheritance, inheritanceMember, false)); + inheritanceInfoList.add(DeclAndCtorInfo(m_astBuilder, this, typeOfInheritance, inheritanceMember, false)); } DeclAndCtorInfo structDeclInfo = DeclAndCtorInfo(m_astBuilder, this, structDecl, nullptr, false); @@ -7833,8 +7833,8 @@ namespace Slang continue; auto seqStmtChild = m_astBuilder->create(); - seqStmtChild->stmts.reserve(inheritanceDefaultCtorList.getCount()); - for (auto& declInfo : inheritanceDefaultCtorList) + seqStmtChild->stmts.reserve(inheritanceInfoList.getCount()); + for (auto& declInfo : inheritanceInfoList) { if (!declInfo.m_defaultCtor) continue; @@ -7931,10 +7931,11 @@ namespace Slang // Pre-calculate if we have a base-type and its associated ctor-list // We also must ensure inheritance-decl is checked, else we may not have up-to-date 'DerivativeMemberAttribute' modifiers DeclAndCtorInfo* baseCtorInfo = nullptr; - for(auto i : inheritanceDefaultCtorList) + for(auto& i : inheritanceInfoList) { ensureDecl(i.m_inheritanceDecl, DeclCheckState::DefinitionChecked); - baseCtorInfo = &i; + if(as(i.m_parent)) + baseCtorInfo = &i; } // Insert parameters as values for member-wise init expression. @@ -10390,10 +10391,17 @@ namespace Slang List publicPrivateInternalCtorArgs; // Harvest parameters which map to the base type ctor. - if(auto baseStructRef = findBaseStructDeclRef(m_astBuilder, structDecl)) + // Note: assumes 1 structDecl, N number inheritance decl + for (auto inheritanceMember : structDecl->getMembersOfType()) { - auto baseStruct = baseStructRef.getDecl(); - DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct,DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; + auto declRefType = as(inheritanceMember->base.type); + if (!declRefType) + continue; + auto baseStruct = as(declRefType->getDeclRef().getDecl()); + if (!baseStruct) + continue; + + DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; ConstructorDecl* ctorForPublic = nullptr; ConstructorDecl* ctorForInternal = nullptr; From 465e07cbd44904bf1629d4c3a814d020aa01c7c3 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 21 Aug 2024 00:26:41 -0400 Subject: [PATCH 027/100] cleanup and fix invalid test + refine auto-diff code --- source/slang/slang-check-decl.cpp | 10 ++++--- source/slang/slang-ir-legalize-types.cpp | 29 ++++++++++++++++++--- source/slang/slang-legalize-types.h | 16 ++++++++++++ tests/autodiff/make-struct-mixed-type.slang | 4 ++- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 5673ffb230..796a5a1e58 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1856,7 +1856,10 @@ namespace Slang ctor->members.add(param); } addVisibilityModifier(m_astBuilder, ctor, visibility); - addModifier(ctor, m_astBuilder->create()); + + if (visitor->isTypeDifferentiable(ctor->returnType.type)) + addModifier(ctor, m_astBuilder->create()); + decl->addMember(ctor); return ctor; } @@ -8058,11 +8061,10 @@ namespace Slang } // Check for differentiability, if we cannot diff this member attach a no_diff attribute. - if (( !this->isTypeDifferentiable(member->type) || !member->hasModifier()) && !param->hasModifier()) + if (!member->hasModifier() || member->hasModifier()) addModifier(param, m_astBuilder->create()); - //Manage CUDA host modifier based on inheritance - //containsType + // Manage CUDA host modifier based on inheritance if (!foundCudaHostModifier && containsTargetType(m_astBuilder, member->type.type)) { foundCudaHostModifier = true; diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp index 4d77598813..a90a94d9bd 100644 --- a/source/slang/slang-ir-legalize-types.cpp +++ b/source/slang/slang-ir-legalize-types.cpp @@ -343,8 +343,20 @@ struct LegalCallBuilder // result type of the function, so we know that // the legalization funciton/call will use a `void` // result type. - // - _emitCall(m_context->builder->getVoidType()); + + // If our call is in global scope (initializer) we should + // hoist the call into the start of every entry-point + if (!m_context->builder->getInsertLoc().getInst()->getParent() + || m_context->builder->getInsertLoc().getInst()->getParent()->getOp() == kIROp_Module) + { + for (auto i : m_context->getEntryPoints()) + { + m_context->builder->setInsertBefore(i->getFirstOrdinaryInst()); + _emitCall(m_context->builder->getVoidType()); + } + } + else + _emitCall(m_context->builder->getVoidType()); return resultVal; } break; @@ -370,10 +382,19 @@ struct LegalCallBuilder auto simpleType = resultType.getSimple(); auto builder = m_context->builder; - // Recall that a local variable in our IR represents a *pointer* + // Recall that a variable in our IR represents a *pointer* // to storage of the appropriate type. // - auto varPtr = builder->emitVar(simpleType); + IRInst* varPtr = nullptr; + if (m_call->parent->getOp() == kIROp_Module) + { + // If we were going to emit an IRVar in global scope, emit a GlobalVar instead + varPtr = builder->createGlobalVar(simpleType); + } + else + { + varPtr = builder->emitVar(simpleType); + } // We need to pass that pointer as an argument to our new // `call` instruction, so that it can receive the value diff --git a/source/slang/slang-legalize-types.h b/source/slang/slang-legalize-types.h index f954e2b251..a69f70d907 100644 --- a/source/slang/slang-legalize-types.h +++ b/source/slang/slang-legalize-types.h @@ -649,6 +649,22 @@ struct IRTypeLegalizationContext List activePointerValues; + List entryPoints; + + List& getEntryPoints() + { + if (entryPoints.getCount() == 0) + { + for (auto i : module->getGlobalInsts()) + { + if (auto func = as(i)) + if (i->findDecoration()) + entryPoints.add(func); + } + } + return entryPoints; + } + IRBuilder* getBuilder() { return builder; } /// Customization point to decide what types are "special." diff --git a/tests/autodiff/make-struct-mixed-type.slang b/tests/autodiff/make-struct-mixed-type.slang index bc966eff7b..680852f420 100644 --- a/tests/autodiff/make-struct-mixed-type.slang +++ b/tests/autodiff/make-struct-mixed-type.slang @@ -27,8 +27,10 @@ float f(MixedType m) void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID) { MixedType v = { 0, 2.0 }; - MixedType.Differential dv = { 0.0 }; + MixedType.Differential dv = { 0.0, 0.0 }; + var p = diffPair(v, dv); __bwd_diff(f)(p, 1.0); outputBuffer[0] = p.d.field; + outputBuffer[1] = dv.noDiffField; } \ No newline at end of file From f26ea600d96467cc8e2eebb0695729bd28775a34 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:03:55 -0400 Subject: [PATCH 028/100] clean-up --- source/slang/slang-check-decl.cpp | 11 ++++++++--- source/slang/slang-doc-ast.cpp | 1 - source/slang/slang-ir-legalize-types.cpp | 16 ++-------------- source/slang/slang-legalize-types.h | 16 ---------------- 4 files changed, 10 insertions(+), 34 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 796a5a1e58..469b952010 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1858,8 +1858,12 @@ namespace Slang addVisibilityModifier(m_astBuilder, ctor, visibility); if (visitor->isTypeDifferentiable(ctor->returnType.type)) + { addModifier(ctor, m_astBuilder->create()); - + addModifier(ctor, m_astBuilder->create()); + } + else + addModifier(ctor, m_astBuilder->create()); decl->addMember(ctor); return ctor; } @@ -8060,8 +8064,9 @@ namespace Slang member = members[memberIndex++].getDecl(); } - // Check for differentiability, if we cannot diff this member attach a no_diff attribute. - if (!member->hasModifier() || member->hasModifier()) + // Check for differentiability of member. 'no_diff' and 'DerivativeMemberAttribute' additions + // are handled by checking all 'InheritanceDecl's earlier in 'visitAggTypeDecl' + if (!member->hasModifier()) addModifier(param, m_astBuilder->create()); // Manage CUDA host modifier based on inheritance diff --git a/source/slang/slang-doc-ast.cpp b/source/slang/slang-doc-ast.cpp index 61ae77c62e..4d35f32be2 100644 --- a/source/slang/slang-doc-ast.cpp +++ b/source/slang/slang-doc-ast.cpp @@ -48,7 +48,6 @@ namespace Slang { } } - bool shouldDocumentDecl(Decl* decl) { return !getText(decl->getName()).startsWith("$__syn") && !decl->hasModifier(); diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp index a90a94d9bd..9ca463b446 100644 --- a/source/slang/slang-ir-legalize-types.cpp +++ b/source/slang/slang-ir-legalize-types.cpp @@ -343,20 +343,8 @@ struct LegalCallBuilder // result type of the function, so we know that // the legalization funciton/call will use a `void` // result type. - - // If our call is in global scope (initializer) we should - // hoist the call into the start of every entry-point - if (!m_context->builder->getInsertLoc().getInst()->getParent() - || m_context->builder->getInsertLoc().getInst()->getParent()->getOp() == kIROp_Module) - { - for (auto i : m_context->getEntryPoints()) - { - m_context->builder->setInsertBefore(i->getFirstOrdinaryInst()); - _emitCall(m_context->builder->getVoidType()); - } - } - else - _emitCall(m_context->builder->getVoidType()); + // + _emitCall(m_context->builder->getVoidType()); return resultVal; } break; diff --git a/source/slang/slang-legalize-types.h b/source/slang/slang-legalize-types.h index a69f70d907..f954e2b251 100644 --- a/source/slang/slang-legalize-types.h +++ b/source/slang/slang-legalize-types.h @@ -649,22 +649,6 @@ struct IRTypeLegalizationContext List activePointerValues; - List entryPoints; - - List& getEntryPoints() - { - if (entryPoints.getCount() == 0) - { - for (auto i : module->getGlobalInsts()) - { - if (auto func = as(i)) - if (i->findDecoration()) - entryPoints.add(func); - } - } - return entryPoints; - } - IRBuilder* getBuilder() { return builder; } /// Customization point to decide what types are "special." From 5b020195fbe2144ecada40d12fe967a079fab598 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:23:31 -0400 Subject: [PATCH 029/100] default construct structs without an initExpr (as per how Slang is supposed to work) --- source/slang/slang-check-decl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 469b952010..4879c32512 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1958,7 +1958,7 @@ namespace Slang _validateCircularVarDefinition(varDecl); } // all structDecl's need to be set to a default value (else it is a compile error for HLSL) - else if (as(type)) + else if (as(type) && as(as(type)->getDeclRef())) varDecl->initExpr = constructDefaultInitExprForVar(this, varDecl->type, varDecl); else { From 3e558d705cf0711b77713c7b6fdfd95c87406b8a Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:22:51 -0400 Subject: [PATCH 030/100] redo reverse-addr-elim test properly without partial init --- source/slang/slang-check-decl.cpp | 3 --- tests/autodiff/reverse-addr-eliminate.slang | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 4879c32512..308aedb026 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1957,9 +1957,6 @@ namespace Slang varDecl->setCheckState(DeclCheckState::DefinitionChecked); _validateCircularVarDefinition(varDecl); } - // all structDecl's need to be set to a default value (else it is a compile error for HLSL) - else if (as(type) && as(as(type)->getDeclRef())) - varDecl->initExpr = constructDefaultInitExprForVar(this, varDecl->type, varDecl); else { // If a variable doesn't have an explicit initial-value diff --git a/tests/autodiff/reverse-addr-eliminate.slang b/tests/autodiff/reverse-addr-eliminate.slang index e49a0f691e..33c5ba8bf3 100644 --- a/tests/autodiff/reverse-addr-eliminate.slang +++ b/tests/autodiff/reverse-addr-eliminate.slang @@ -53,7 +53,7 @@ A f(A a, int i) [numthreads(1, 1, 1)] void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) { - A a; + A a = {}; a.x = 1; a.y = 2; From fd7999f8fe9a8cae050650f8a17950f2a3298716 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:35:18 -0400 Subject: [PATCH 031/100] do not error if unexpected expr is found since this is not exactly 'wrong' --- source/slang/slang-check-conversion.cpp | 6 ++---- source/slang/slang-check-impl.h | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index a65cbbc6d8..88f0a3dddf 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -564,13 +564,11 @@ namespace Slang InvokeExpr* constructorExpr = m_astBuilder->create(); constructorExpr->loc = fromInitializerListExpr->loc; - constructorExpr->functionExpr = CheckTerm(callee); + constructorExpr->functionExpr = callee; constructorExpr->arguments.addRange(coercedArgs); constructorExpr->type = toType; - //TODO: - - *outToExpr = CheckInvokeExprWithCheckedOperands(constructorExpr); + *outToExpr = CheckTerm(constructorExpr); } return true; } diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 0ce37b378c..0add61b182 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -2756,12 +2756,12 @@ namespace Slang // deal with this cases here, even if they are no-ops. // + // Do not error and just return since a term may + // be checked so it can be resolved into a valid + // term (argument of an 'Invoke' for example) #define CASE(NAME) \ Expr* visit##NAME(NAME* expr) \ { \ - if (!getShared()->isInLanguageServer()) \ - SLANG_DIAGNOSE_UNEXPECTED(getSink(), expr, "should not appear in input syntax"); \ - expr->type = m_astBuilder->getErrorType(); \ return expr; \ } From 36ec8cea4da5dba977f924d9414936d573426a2b Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:06:35 -0400 Subject: [PATCH 032/100] auto-diff fix --- source/slang/slang-check-decl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 308aedb026..0ff92d5215 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -8047,6 +8047,7 @@ namespace Slang paramExpr->type = paramType; paramExpr->loc = param->loc; + bool treatCtorAsDifferentiable = ctor->hasModifier(); // Do not map a variable which is not visible // Do not map a read-only variable for default-init // Do not map compiler generated 'internal processing' variable @@ -8063,7 +8064,7 @@ namespace Slang // Check for differentiability of member. 'no_diff' and 'DerivativeMemberAttribute' additions // are handled by checking all 'InheritanceDecl's earlier in 'visitAggTypeDecl' - if (!member->hasModifier()) + if (!treatCtorAsDifferentiable && !member->hasModifier()) addModifier(param, m_astBuilder->create()); // Manage CUDA host modifier based on inheritance From d88849cf38448b1fe030cfeb15f767b3a6a770a3 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 26 Aug 2024 14:45:09 -0400 Subject: [PATCH 033/100] undo code which should not be apart of this PR --- source/slang/slang-ir-legalize-types.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp index 9ca463b446..4d77598813 100644 --- a/source/slang/slang-ir-legalize-types.cpp +++ b/source/slang/slang-ir-legalize-types.cpp @@ -370,19 +370,10 @@ struct LegalCallBuilder auto simpleType = resultType.getSimple(); auto builder = m_context->builder; - // Recall that a variable in our IR represents a *pointer* + // Recall that a local variable in our IR represents a *pointer* // to storage of the appropriate type. // - IRInst* varPtr = nullptr; - if (m_call->parent->getOp() == kIROp_Module) - { - // If we were going to emit an IRVar in global scope, emit a GlobalVar instead - varPtr = builder->createGlobalVar(simpleType); - } - else - { - varPtr = builder->emitVar(simpleType); - } + auto varPtr = builder->emitVar(simpleType); // We need to pass that pointer as an argument to our new // `call` instruction, so that it can receive the value From 01274fb7c6d80974520d3a67d6ebf367d760ac93 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 26 Aug 2024 20:49:01 -0400 Subject: [PATCH 034/100] change when we zero-init to stay backwards compatible --- source/slang/slang-check-decl.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index ea54d84f65..53f46cae9a 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7908,17 +7908,38 @@ namespace Slang for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { auto ctor = ctorInfo.m_ctor; + ThisExpr* thisExpr = m_astBuilder->create(); thisExpr->scope = ctor->ownedScope; thisExpr->type = ctor->returnType.type; auto seqStmtChild = m_astBuilder->create(); seqStmtChild->stmts.reserve(structDecl->members.getCount()); + + /// Default Ctor's which are *synthisized* must zero-initialize members since otherwise + /// '{}' will not work as expected for a user. This variable checks for the ctor attributes + bool isDefaultSynthisizedCtor = ctor->containsOption(ConstructorTags::Synthesized) && ctor->getParameters().getCount() == 0; + for (auto varDeclBaseRef : getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance)) { auto varDeclBase = varDeclBaseRef.getDecl(); - if (!varDeclBase->initExpr) - continue; + auto varType = varDeclBase->type.type; + //bool canCopy = !isOpaqueHandleType(varType) + //&& !(as(varType) && as(varType)->getDeclRef().getDecl()->findModifier()) + //; + Expr* initExpr = varDeclBase->initExpr; + if (!initExpr) + { + if (!isDefaultSynthisizedCtor + //&& canCopy + ) + continue; + auto defaultExpr = m_astBuilder->create(); + defaultExpr->type = QualType(varDeclBase->type); + defaultExpr->loc = varDeclBase->loc; + initExpr = defaultExpr; + } + MemberExpr* memberExpr = m_astBuilder->create(); memberExpr->baseExpression = thisExpr; @@ -7930,7 +7951,7 @@ namespace Slang auto assign = m_astBuilder->create(); assign->left = memberExpr; - assign->right = varDeclBase->initExpr; + assign->right = initExpr; assign->loc = varDeclBase->loc; auto stmt = m_astBuilder->create(); From c9b70801ea7648158382049c2b0fa7630244c6bf Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 26 Aug 2024 22:02:11 -0400 Subject: [PATCH 035/100] fix warning --- source/slang/slang-check-decl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 53f46cae9a..f221d06794 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7923,7 +7923,7 @@ namespace Slang for (auto varDeclBaseRef : getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance)) { auto varDeclBase = varDeclBaseRef.getDecl(); - auto varType = varDeclBase->type.type; + //auto varType = varDeclBase->type.type; //bool canCopy = !isOpaqueHandleType(varType) //&& !(as(varType) && as(varType)->getDeclRef().getDecl()->findModifier()) //; From 83af02384f05797013089c41037c1cb2bfebc824 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 27 Aug 2024 14:08:58 -0400 Subject: [PATCH 036/100] added a special zero-init function to handle `{}` case --- source/slang/slang-ast-modifier.h | 3 + source/slang/slang-check-conversion.cpp | 2 +- source/slang/slang-check-decl.cpp | 259 ++++++++++++++---- source/slang/slang-check-impl.h | 2 + source/slang/slang-constructor-utility.cpp | 42 +++ .../initializer-lists/cstyle-init-list.slang | 4 +- .../initializer-lists/default-init-list.slang | 32 +++ ...ynth-constructor-conflicting-default.slang | 4 +- .../initializer-lists/readonly-member.slang | 5 +- .../struct-swizzle-initializer-list.slang | 4 +- 10 files changed, 290 insertions(+), 67 deletions(-) create mode 100644 tests/language-feature/initializer-lists/default-init-list.slang diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index c890b874cb..953ccf835a 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -38,6 +38,9 @@ class ToBeSynthesizedModifier : public Modifier {SLANG_AST_CLASS(ToBeSynthesized // Marks that the definition of a decl is synthesized. class SynthesizedModifier : public Modifier { SLANG_AST_CLASS(SynthesizedModifier) }; +// Marks that the definition of a decl is synthesized. +class ZeroInitModifier : public Modifier { SLANG_AST_CLASS(ZeroInitModifier) }; + // Marks a synthesized variable as local temporary variable. class LocalTempVarModifier : public Modifier { SLANG_AST_CLASS(LocalTempVarModifier) }; diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 88f0a3dddf..c4248a5137 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -480,7 +480,7 @@ namespace Slang { if (outToExpr) { - *outToExpr = constructDefaultInitExprForVar(this, (TypeExp)toType, nullptr); + *outToExpr = constructZeroInitListFunc(this, toStructDecl, toType); (*outToExpr)->loc = fromInitializerListExpr->loc; } return true; diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index f221d06794..1b83d42c0f 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1818,7 +1818,6 @@ namespace Slang DeclVisibility visibility) { auto ctor = m_astBuilder->create(); - addModifier(ctor, m_astBuilder->create()); auto ctorName = visitor->getName("$init"); ctor->ownedScope = m_astBuilder->create(); ctor->ownedScope->containerDecl = ctor; @@ -1839,6 +1838,7 @@ namespace Slang body->closingSourceLoc = ctor->closingSourceLoc; ctor->body = body; body->body = m_astBuilder->create(); + addModifier(ctor, m_astBuilder->create()); ctor->addOption(ConstructorTags::Synthesized); // kIROp_TorchTensorType must only refer to its own type through Host functions @@ -7785,10 +7785,13 @@ namespace Slang auto structDecl = as(aggTypeDecl); if (!structDecl) return; + + auto structDeclType = DeclRefType::create(m_astBuilder, structDecl); + /// Collect ctor info struct DeclAndCtorInfo { - AggTypeDecl* m_parent; + AggTypeDecl* m_inheritanceBaseDecl; InheritanceDecl* m_inheritanceDecl; ConstructorDecl* m_defaultCtor = nullptr; @@ -7802,10 +7805,10 @@ namespace Slang DeclAndCtorInfo() { } - DeclAndCtorInfo(ASTBuilder* m_astBuilder, SemanticsVisitor* visitor, AggTypeDecl* parent, InheritanceDecl* inheritanceDecl, const bool getOnlyDefault) : m_parent(parent), m_inheritanceDecl(inheritanceDecl) + DeclAndCtorInfo(ASTBuilder* m_astBuilder, SemanticsVisitor* visitor, AggTypeDecl* inheritanceBaseDecl, InheritanceDecl* inheritanceDecl, const bool getOnlyDefault) : m_inheritanceBaseDecl(inheritanceBaseDecl), m_inheritanceDecl(inheritanceDecl) { // only get ctor info from structDecl - StructDecl* structDecl = as(parent); + StructDecl* structDecl = as(m_inheritanceBaseDecl); if (!structDecl) return; @@ -7834,9 +7837,9 @@ namespace Slang } DeclAndCtorInfo structDeclInfo = DeclAndCtorInfo(m_astBuilder, this, structDecl, nullptr, false); - // ensure all varDecl members are processed up to SemanticsBodyVisitor so we can be sure that if init expressions - // of members are to be synthisised, they are. - bool isDefaultInitializableType = isSubtype(DeclRefType::create(m_astBuilder, structDecl), m_astBuilder->getDefaultInitializableType(), IsSubTypeOptions::None); + /// ensure all varDecl members are processed up to SemanticsBodyVisitor so we can be sure that if init expressions + /// of members are to be synthisised, they are. + bool isDefaultInitializableType = isSubtype(structDeclType, m_astBuilder->getDefaultInitializableType(), IsSubTypeOptions::None); for (auto m : structDecl->members) { auto varDeclBase = as(m); @@ -7851,7 +7854,7 @@ namespace Slang Dictionary cachedDeclToCheckedVar; - // Insert 'this->base->__init()' into 'this->__init()'. + /// Insert 'this->base->__init()' into 'this->__init()'. for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { auto ctor = ctorInfo.m_ctor; @@ -7904,7 +7907,12 @@ namespace Slang seqStmt->stmts.insert(ctorInfo.m_insertOffset++, seqStmtChild); } - // Assign member variable init expressions + /// Collect all 'per instance' members of our struct + List> membersOfStructDeclInstance; + for (auto i : getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance)) + membersOfStructDeclInstance.add(i); + + /// Assign member variable init expressions for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { auto ctor = ctorInfo.m_ctor; @@ -7916,30 +7924,13 @@ namespace Slang auto seqStmtChild = m_astBuilder->create(); seqStmtChild->stmts.reserve(structDecl->members.getCount()); - /// Default Ctor's which are *synthisized* must zero-initialize members since otherwise - /// '{}' will not work as expected for a user. This variable checks for the ctor attributes - bool isDefaultSynthisizedCtor = ctor->containsOption(ConstructorTags::Synthesized) && ctor->getParameters().getCount() == 0; - - for (auto varDeclBaseRef : getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance)) + for (auto varDeclBaseRef : membersOfStructDeclInstance) { auto varDeclBase = varDeclBaseRef.getDecl(); - //auto varType = varDeclBase->type.type; - //bool canCopy = !isOpaqueHandleType(varType) - //&& !(as(varType) && as(varType)->getDeclRef().getDecl()->findModifier()) - //; Expr* initExpr = varDeclBase->initExpr; if (!initExpr) - { - if (!isDefaultSynthisizedCtor - //&& canCopy - ) - continue; - auto defaultExpr = m_astBuilder->create(); - defaultExpr->type = QualType(varDeclBase->type); - defaultExpr->loc = varDeclBase->loc; - initExpr = defaultExpr; - } - + continue; + MemberExpr* memberExpr = m_astBuilder->create(); memberExpr->baseExpression = thisExpr; @@ -7978,18 +7969,37 @@ namespace Slang seqStmt->stmts.insert(ctorInfo.m_insertOffset++, seqStmtChild); } - // Note: we assume only 1 inheritance decl currently. - // Pre-calculate if we have a base-type and its associated ctor-list - // We also must ensure inheritance-decl is checked, else we may not have up-to-date 'DerivativeMemberAttribute' modifiers - DeclAndCtorInfo* baseCtorInfo = nullptr; + /// Note: we assume only 1 inheritance decl currently. + /// Pre-calculate if we have a base-type and its associated ctor-list + /// We also must ensure inheritance-decl is checked, else we may not have up-to-date 'DerivativeMemberAttribute' modifiers + DeclAndCtorInfo* baseStructInfo = nullptr; for(auto& i : inheritanceInfoList) { ensureDecl(i.m_inheritanceDecl, DeclCheckState::DefinitionChecked); - if(as(i.m_parent)) - baseCtorInfo = &i; + if(as(i.m_inheritanceBaseDecl)) + baseStructInfo = &i; } - // Insert parameters as values for member-wise init expression. + /// pre-calculate any requirements of a CudaHostAttribute + HashSet requiresCudaHostModifier; + for (auto member : membersOfStructDeclInstance) + if (containsTargetType(m_astBuilder, member.getDecl()->type.type)) + requiresCudaHostModifier.add(member.getDecl()); + auto addCudaHostModifierIfRequired = [&](FunctionDeclBase* func, VarDeclBase* member, bool& foundCudaHostModifier) + { + // Manage CUDA host modifier based on inheritance + if (!foundCudaHostModifier && requiresCudaHostModifier.contains(member)) + { + foundCudaHostModifier = true; + addModifier(func, m_astBuilder->create()); + } + // + + }; + + + + /// Insert parameters as values for member-wise init expression. for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { auto ctor = ctorInfo.m_ctor; @@ -8001,7 +8011,7 @@ namespace Slang auto paramList = ctor->getParameters(); Index memberIndex = 0; - auto members = getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance); + auto members = membersOfStructDeclInstance; auto seqStmt = _ensureCtorBodyIsSeqStmt(m_astBuilder, ctor); auto seqStmtChild = m_astBuilder->create(); @@ -8019,16 +8029,16 @@ namespace Slang auto param = paramList[paramIndex]; // If we have a base type, the first arg is a 'base->__init(...)'. We need to find this 'base->__init(...)' // and assign the parameters needed to call '__init(...)' - if (paramIndex == 0 && baseCtorInfo && baseCtorInfo->m_ctorInfoList.getCount() > 0) + if (paramIndex == 0 && baseStructInfo && baseStructInfo->m_ctorInfoList.getCount() > 0) { - auto baseStruct = baseCtorInfo->m_parent; + auto baseStruct = baseStructInfo->m_inheritanceBaseDecl; // First find a member-wise 'base->__init()' which maps to this current ctor being filled ConstructorDecl* baseCtor = nullptr; ConstructorTags memberwiseCtorToCall = ConstructorTags::MemberwiseCtorForPublicVisibility; if (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) memberwiseCtorToCall = ConstructorTags::MemberwiseCtorForInternalVisibility; - for (auto& i : baseCtorInfo->m_ctorInfoList) + for (auto& i : baseStructInfo->m_ctorInfoList) { if (i.m_ctor->containsOption(memberwiseCtorToCall)) { @@ -8090,7 +8100,6 @@ namespace Slang paramExpr->type = paramType; paramExpr->loc = param->loc; - bool treatCtorAsDifferentiable = ctor->hasModifier(); // Do not map a variable which is not visible // Do not map a read-only variable for default-init // Do not map compiler generated 'internal processing' variable @@ -8105,18 +8114,12 @@ namespace Slang member = members[memberIndex++].getDecl(); } - // Check for differentiability of member. 'no_diff' and 'DerivativeMemberAttribute' additions - // are handled by checking all 'InheritanceDecl's earlier in 'visitAggTypeDecl' - if (!treatCtorAsDifferentiable && !member->hasModifier()) + // Check for differentiability of member. checking all 'InheritanceDecl's earlier in 'visitAggTypeDecl' + // propegates DerivativeMemberAtribute to derivative containing attributes. + if (!ctor->hasModifier() && !member->hasModifier()) addModifier(param, m_astBuilder->create()); - // Manage CUDA host modifier based on inheritance - if (!foundCudaHostModifier && containsTargetType(m_astBuilder, member->type.type)) - { - foundCudaHostModifier = true; - addModifier(ctor, m_astBuilder->create()); - } - // + addCudaHostModifierIfRequired(ctor, member, foundCudaHostModifier); MemberExpr* memberExpr = m_astBuilder->create(); memberExpr->baseExpression = thisExpr; @@ -8140,25 +8143,138 @@ namespace Slang seqStmt->stmts.insert(ctorInfo.m_insertOffset++, seqStmtChild); } - // Compiler generated ctor may be destroyed + /// Compiler generated ctor may be destroyed + bool destroyedDefaultCtor = false; if(structDeclInfo.m_defaultCtor && structDeclInfo.m_defaultCtor->containsOption(ConstructorTags::Synthesized)) { - bool destroy = false; if (!structDeclInfo.m_defaultCtor->body) - destroy = true; + destroyedDefaultCtor = true; else if (auto block = as(structDeclInfo.m_defaultCtor->body)) { if (as(block->body)->stmts.getCount() == 0) - destroy = true; + destroyedDefaultCtor = true; } - if (destroy) + if (destroyedDefaultCtor) { structDecl->members.remove(structDeclInfo.m_defaultCtor); + if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) + structDecl->members.remove(zeroInitListFunc); + structDecl->invalidateMemberDictionary(); structDecl->buildMemberDictionary(); + + } + } + + // Only generate '$ZeroInit' if synthisized `__init()` exists + if (!destroyedDefaultCtor) + { + if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) + { + SLANG_ASSERT(zeroInitListFunc->getParameters().getCount() == 0); + SLANG_ASSERT(zeroInitListFunc->findModifier()); + + SLANG_ASSERT(as(zeroInitListFunc->body)); + auto block = as(zeroInitListFunc->body); + SLANG_ASSERT(as(block->body)); + auto seqStmt = as(block->body); + + bool foundCudaHostModifier = false; + + auto defaultConstructExpr = m_astBuilder->create(); + defaultConstructExpr->type = structDeclType; + defaultConstructExpr->loc = seqStmt->loc; + + auto structVarDecl = m_astBuilder->create(); + structVarDecl->type = TypeExp(structDeclType); + structVarDecl->initExpr = defaultConstructExpr; + structVarDecl->parentDecl = zeroInitListFunc; + structVarDecl->loc = seqStmt->loc; + ensureDecl(structVarDecl, DeclCheckState::DefaultConstructorReadyForUse); + + auto structVarDeclExpr = m_astBuilder->create(); + structVarDeclExpr->declRef = structVarDecl->getDefaultDeclRef(); + structVarDeclExpr->name = structVarDecl->getName(); + structVarDeclExpr->loc = structVarDecl->loc; + structVarDeclExpr->type = GetTypeForDeclRef(structVarDecl, structVarDecl->loc); + + structVarDeclExpr->type.isLeftValue = true; + structVarDeclExpr->scope = zeroInitListFunc->ownedScope; + + auto structAssignExpr = m_astBuilder->create(); + structAssignExpr->left = structVarDeclExpr; + structAssignExpr->right = defaultConstructExpr; + auto structAssignExprStmt = m_astBuilder->create(); + structAssignExprStmt->expression = structAssignExpr; + structAssignExprStmt->loc = seqStmt->loc; + seqStmt->stmts.add(structAssignExprStmt); + + // Assign $ZeroInit of inheritanceDecl + if (baseStructInfo) + { + if (auto baseStructDecl = as(baseStructInfo->m_inheritanceBaseDecl)) + { + MemberExpr* memberExpr = m_astBuilder->create(); + memberExpr->baseExpression = structVarDeclExpr; + memberExpr->declRef = baseStructInfo->m_inheritanceDecl->getDefaultDeclRef(); + memberExpr->scope = zeroInitListFunc->ownedScope; + memberExpr->loc = baseStructInfo->m_inheritanceDecl->loc; + memberExpr->name = baseStructInfo->m_inheritanceDecl->getName(); + memberExpr->type = GetTypeForDeclRef(baseStructInfo->m_inheritanceDecl, baseStructInfo->m_inheritanceDecl->loc); + auto checkedMemberVarExpr = CheckTerm(memberExpr); + + Expr* zeroInitFunc = constructZeroInitListFunc(this, baseStructDecl, DeclRefType::create(m_astBuilder, baseStructInfo->m_inheritanceDecl)); + auto assign = m_astBuilder->create(); + assign->left = checkedMemberVarExpr; + assign->right = zeroInitFunc; + auto stmt = m_astBuilder->create(); + stmt->expression = assign; + stmt->loc = seqStmt->loc; + seqStmt->stmts.add(stmt); + } + } + + // Assign initExpr to all members + for (auto memberRef : membersOfStructDeclInstance) + { + auto member = memberRef.getDecl(); + auto initExpr = member->initExpr; + if (!initExpr) + continue; + + MemberExpr* memberExpr = m_astBuilder->create(); + memberExpr->baseExpression = structVarDeclExpr; + memberExpr->declRef = member->getDefaultDeclRef(); + memberExpr->scope = zeroInitListFunc->ownedScope; + memberExpr->loc = member->loc; + memberExpr->name = member->getName(); + memberExpr->type = GetTypeForDeclRef(member, member->loc); + auto checkedMemberVarExpr = CheckTerm(memberExpr); + if (!checkedMemberVarExpr->type.isLeftValue) + continue; + + auto assign = m_astBuilder->create(); + assign->left = checkedMemberVarExpr; + assign->right = initExpr; + assign->loc = checkedMemberVarExpr->loc; + + auto stmt = m_astBuilder->create(); + stmt->expression = assign; + stmt->loc = assign->loc; + + addCudaHostModifierIfRequired(zeroInitListFunc, member, foundCudaHostModifier); + seqStmt->stmts.add(stmt); + } + + auto returnStmt = m_astBuilder->create(); + returnStmt->loc = structVarDeclExpr->loc; + returnStmt->expression = structVarDeclExpr; + + seqStmt->stmts.add(returnStmt); } } + } void SemanticsDeclHeaderVisitor::cloneModifiers(Decl* dest, Decl* src) @@ -10424,13 +10540,42 @@ namespace Slang void SemanticsDeclAttributesVisitor::visitStructDecl(StructDecl* structDecl) { - // Add an empty default Ctor if missing + // Add an empty default-Ctor and $ZeroInit if missing. ConstructorDecl* defaultCtor = nullptr; List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); if (!defaultCtor) { defaultCtor = _createCtor(this, m_astBuilder, structDecl, {}, getDeclVisibility(structDecl)); ctorList.add(defaultCtor); + + // $ZeroInit is a synthisized static-function only used if a user does not define a + // default ctor. Use of $ZeroInit is only for `{}` to avoid hacks. + auto zeroInitFunc = m_astBuilder->create(); + auto ctorName = getName("$ZeroInit"); + zeroInitFunc->ownedScope = m_astBuilder->create(); + zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; + zeroInitFunc->ownedScope->parent = getScope(structDecl); + zeroInitFunc->parentDecl = structDecl; + zeroInitFunc->loc = structDecl->loc; + zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; + zeroInitFunc->nameAndLoc.name = ctorName; + zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; + zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); + auto body = m_astBuilder->create(); + body->scopeDecl = m_astBuilder->create(); + body->scopeDecl->ownedScope = m_astBuilder->create(); + body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); + body->scopeDecl->parentDecl = zeroInitFunc; + body->scopeDecl->loc = zeroInitFunc->loc; + body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; + body->closingSourceLoc = zeroInitFunc->closingSourceLoc; + zeroInitFunc->body = body; + body->body = m_astBuilder->create(); + addModifier(zeroInitFunc, m_astBuilder->create()); + addModifier(zeroInitFunc, m_astBuilder->create()); + addModifier(zeroInitFunc, m_astBuilder->create()); + addModifier(zeroInitFunc, m_astBuilder->create()); + structDecl->addMember(zeroInitFunc); } // Add an empty constructor for all combinations of visibility and access diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 0add61b182..9e6861159f 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -2948,6 +2948,8 @@ namespace Slang bool DiagnoseIsAllowedInitExpr(VarDeclBase* varDecl, DiagnosticSink* sink); bool isDefaultInitializable(Type* varDeclType, VarDeclBase* associatedDecl); Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, TypeExp varDeclType, VarDeclBase* decl); + Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType); + FuncDecl* findZeroInitListFunc(StructDecl* structDecl); DeclRefBase* _getDeclRefFromVal(Val* val); diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index 1d8f5a42fe..e8f3c1dc09 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -146,5 +146,47 @@ namespace Slang return defaultCall; } } + + FuncDecl* findZeroInitListFunc(StructDecl* structDecl) + { + for (auto funcDecl : structDecl->getMembersOfType()) + { + if (!funcDecl->findModifier()) + continue; + return funcDecl; + } + return nullptr; + } + + Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType) + { + SLANG_ASSERT(structDecl); + + // Try to get $ZeroInit + if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) + { + auto* invoke = visitor->getASTBuilder()->create(); + auto member = visitor->getASTBuilder()->getMemberDeclRef(structDecl->getDefaultDeclRef(), zeroInitListFunc); + invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, zeroInitListFunc->loc, nullptr); + invoke->type = structDeclType; + return invoke; + } + + // Try to get default-ctor + if (auto defaultCtor = _getDefaultCtor(structDecl)) + { + auto* invoke = visitor->getASTBuilder()->create(); + auto member = visitor->getASTBuilder()->getMemberDeclRef(structDecl->getDefaultDeclRef(), defaultCtor); + invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->loc, nullptr); + invoke->type = structDeclType; + return invoke; + } + + + // return DefaultConstructExpr + auto* defaultCall = visitor->getASTBuilder()->create(); + defaultCall->type = QualType(structDeclType); + return defaultCall; + } } diff --git a/tests/language-feature/initializer-lists/cstyle-init-list.slang b/tests/language-feature/initializer-lists/cstyle-init-list.slang index c4a7da3296..51a41e38c5 100644 --- a/tests/language-feature/initializer-lists/cstyle-init-list.slang +++ b/tests/language-feature/initializer-lists/cstyle-init-list.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE(filecheck=PASS): -target hlsl -entry computeMain -stage compute +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute struct Test { @@ -7,7 +7,7 @@ struct Test }; -//PASS: computeMain +//CHECK: computeMain RWStructuredBuffer outputBuffer; diff --git a/tests/language-feature/initializer-lists/default-init-list.slang b/tests/language-feature/initializer-lists/default-init-list.slang new file mode 100644 index 0000000000..70cee85c41 --- /dev/null +++ b/tests/language-feature/initializer-lists/default-init-list.slang @@ -0,0 +1,32 @@ +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +public struct Test +{ +//CHECK: = 5 + public uint a = 5; +//CHECK: = 0 + public uint b; +}; + +Test getDefault() +{ + Test test = {}; + return test; +} + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test test = getDefault(); + +//BUF: 1 + outputBuffer[0] = (true + && test.a == 5 + && test.b == 0 + ) ? 1 : 0 + ; +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang b/tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang index 547b3cfb52..73dd55409e 100644 --- a/tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang +++ b/tests/language-feature/initializer-lists/dont-synth-constructor-conflicting-default.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE(filecheck=PASS): -target hlsl -entry computeMain -stage compute +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute struct Test { @@ -12,7 +12,7 @@ struct Test RWStructuredBuffer outputBuffer; -//PASS: computeMain +//CHECK: computeMain [numthreads(1, 1, 1)] void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) diff --git a/tests/language-feature/initializer-lists/readonly-member.slang b/tests/language-feature/initializer-lists/readonly-member.slang index 46dabf48e8..25f620cb06 100644 --- a/tests/language-feature/initializer-lists/readonly-member.slang +++ b/tests/language-feature/initializer-lists/readonly-member.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE(filecheck=PASS): -target hlsl -allow-glsl -entry computeMain -stage compute +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -allow-glsl -entry computeMain -stage compute struct Test { @@ -6,8 +6,7 @@ struct Test writeonly uint b; }; -//PASS: computeMain -//PASS-NOT +//CHECK: computeMain RWStructuredBuffer outputBuffer; diff --git a/tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang b/tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang index 6865073da4..6dc9a9f712 100644 --- a/tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang +++ b/tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang @@ -1,6 +1,6 @@ -//TEST:SIMPLE(filecheck=PASS): -target hlsl -entry computeMain -stage compute +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute -//PASS: computeMain +//CHECK: computeMain RWStructuredBuffer outputBuffer; From 969dff45b12bd14e4bbf85e019f29bfdcaf7c312 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:00:40 -0400 Subject: [PATCH 037/100] fix inheritance with zero-init-list-func and add test --- source/slang/slang-check-decl.cpp | 17 ++------ .../default-init-list-inheritance.slang | 42 +++++++++++++++++++ 2 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 tests/language-feature/initializer-lists/default-init-list-inheritance.slang diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 1b83d42c0f..ee59e9b728 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -8187,6 +8187,7 @@ namespace Slang defaultConstructExpr->loc = seqStmt->loc; auto structVarDecl = m_astBuilder->create(); + addModifier(structVarDecl, m_astBuilder->create()); structVarDecl->type = TypeExp(structDeclType); structVarDecl->initExpr = defaultConstructExpr; structVarDecl->parentDecl = zeroInitListFunc; @@ -8198,9 +8199,8 @@ namespace Slang structVarDeclExpr->name = structVarDecl->getName(); structVarDeclExpr->loc = structVarDecl->loc; structVarDeclExpr->type = GetTypeForDeclRef(structVarDecl, structVarDecl->loc); - structVarDeclExpr->type.isLeftValue = true; - structVarDeclExpr->scope = zeroInitListFunc->ownedScope; + structVarDeclExpr->scope = block->scopeDecl->ownedScope; auto structAssignExpr = m_astBuilder->create(); structAssignExpr->left = structVarDeclExpr; @@ -8215,18 +8215,9 @@ namespace Slang { if (auto baseStructDecl = as(baseStructInfo->m_inheritanceBaseDecl)) { - MemberExpr* memberExpr = m_astBuilder->create(); - memberExpr->baseExpression = structVarDeclExpr; - memberExpr->declRef = baseStructInfo->m_inheritanceDecl->getDefaultDeclRef(); - memberExpr->scope = zeroInitListFunc->ownedScope; - memberExpr->loc = baseStructInfo->m_inheritanceDecl->loc; - memberExpr->name = baseStructInfo->m_inheritanceDecl->getName(); - memberExpr->type = GetTypeForDeclRef(baseStructInfo->m_inheritanceDecl, baseStructInfo->m_inheritanceDecl->loc); - auto checkedMemberVarExpr = CheckTerm(memberExpr); - - Expr* zeroInitFunc = constructZeroInitListFunc(this, baseStructDecl, DeclRefType::create(m_astBuilder, baseStructInfo->m_inheritanceDecl)); + Expr* zeroInitFunc = constructZeroInitListFunc(this, baseStructDecl, baseStructInfo->m_inheritanceDecl->base.type); auto assign = m_astBuilder->create(); - assign->left = checkedMemberVarExpr; + assign->left = coerce(CoercionSite::Initializer, zeroInitFunc->type, structVarDeclExpr); assign->right = zeroInitFunc; auto stmt = m_astBuilder->create(); stmt->expression = assign; diff --git a/tests/language-feature/initializer-lists/default-init-list-inheritance.slang b/tests/language-feature/initializer-lists/default-init-list-inheritance.slang new file mode 100644 index 0000000000..d4feab9d6a --- /dev/null +++ b/tests/language-feature/initializer-lists/default-init-list-inheritance.slang @@ -0,0 +1,42 @@ +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute +//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-vk -compute -shaderobj -xslang -Wno-41021 + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +public struct TestDerived +{ +//CHECK: = 5 + public uint a = 5; +//CHECK: = 0 + public uint b; +} + +public struct Test : TestDerived +{ +//CHECK: = 0 + public uint c; +//CHECK: = 6 + public uint d = 6; +}; + +Test getDefault() +{ + Test test = {}; + return test; +} + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test test = getDefault(); + +//BUF: 1 + outputBuffer[0] = (true + && test.a == 5 + && test.b == 0 + && test.c == 0 + && test.d == 6 + ) ? 1 : 0 + ; +} \ No newline at end of file From dcd90813f7dfc12393e00efb0f8b0ba1aab7ca34 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:50:33 -0400 Subject: [PATCH 038/100] change order of visiting --- source/slang/slang-check-conversion.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index adfae07fa3..6b896f0a93 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -560,7 +560,7 @@ namespace Slang ctorToInvoke->scope = toStructDecl->ownedScope; ctorToInvoke->name = getName(String(toStructDecl->getName()->text)); ctorToInvoke->type = toType; - Expr* callee = ctorToInvoke; + Expr* callee = CheckExpr(ctorToInvoke); InvokeExpr* constructorExpr = m_astBuilder->create(); constructorExpr->loc = fromInitializerListExpr->loc; @@ -568,7 +568,7 @@ namespace Slang constructorExpr->arguments.addRange(coercedArgs); constructorExpr->type = toType; - *outToExpr = CheckTerm(constructorExpr); + *outToExpr = CheckInvokeExprWithCheckedOperands(constructorExpr);//ResolveInvoke(constructorExpr); } return true; } From b1395e1447b1bc4523d8ef3248a0ff89c4ccd9aa Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 28 Aug 2024 00:52:53 -0400 Subject: [PATCH 039/100] add missing auto-diff modifiers --- source/slang/slang-check-decl.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index ee59e9b728..0239a38958 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1810,6 +1810,20 @@ namespace Slang } } + static void addAutoDiffModifiersToFunc( + SemanticsDeclVisitorBase* visitor, + ASTBuilder* m_astBuilder, + FunctionDeclBase* func) + { + if (visitor->isTypeDifferentiable(func->returnType.type)) + { + addModifier(func, m_astBuilder->create()); + addModifier(func, m_astBuilder->create()); + } + else + addModifier(func, m_astBuilder->create()); + } + static ConstructorDecl* _createCtor( SemanticsDeclVisitorBase* visitor, ASTBuilder* m_astBuilder, @@ -1856,14 +1870,7 @@ namespace Slang ctor->members.add(param); } addVisibilityModifier(m_astBuilder, ctor, visibility); - - if (visitor->isTypeDifferentiable(ctor->returnType.type)) - { - addModifier(ctor, m_astBuilder->create()); - addModifier(ctor, m_astBuilder->create()); - } - else - addModifier(ctor, m_astBuilder->create()); + addAutoDiffModifiersToFunc(visitor, m_astBuilder, ctor); decl->addMember(ctor); return ctor; } @@ -10562,6 +10569,8 @@ namespace Slang body->closingSourceLoc = zeroInitFunc->closingSourceLoc; zeroInitFunc->body = body; body->body = m_astBuilder->create(); + + addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); addModifier(zeroInitFunc, m_astBuilder->create()); addModifier(zeroInitFunc, m_astBuilder->create()); addModifier(zeroInitFunc, m_astBuilder->create()); From c9221ea7adb83bfcc935bfc546b3fed604611489 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 28 Aug 2024 01:49:16 -0400 Subject: [PATCH 040/100] fix syntax err --- source/slang/slang-check-decl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index f589902691..cde00d0f97 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7880,10 +7880,10 @@ namespace Slang continue; auto ctorToInvoke = m_astBuilder->create(); - ctorToInvoke->declRef = declInfo.defaultCtor->getDefaultDeclRef(); - ctorToInvoke->name = declInfo.defaultCtor->getName(); - ctorToInvoke->loc = declInfo.defaultCtor->loc; - ctorToInvoke->type = m_astBuilder->getFuncType(ArrayView(), structDeclInfo.defaultCtor->returnType.type); + ctorToInvoke->declRef = declInfo.m_defaultCtor->getDefaultDeclRef(); + ctorToInvoke->name = declInfo.m_defaultCtor->getName(); + ctorToInvoke->loc = declInfo.m_defaultCtor->loc; + ctorToInvoke->type = m_astBuilder->getFuncType(ArrayView(), structDeclInfo.m_defaultCtor->returnType.type); auto invoke = m_astBuilder->create(); invoke->functionExpr = ctorToInvoke; From f55254ad7dd9532e9bdd33c3b258a8ae2411fc0f Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:04:54 -0400 Subject: [PATCH 041/100] fix functor support regression --- source/slang/slang-check-decl.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index cde00d0f97..9194b764a1 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7938,7 +7938,6 @@ namespace Slang if (!initExpr) continue; - MemberExpr* memberExpr = m_astBuilder->create(); memberExpr->baseExpression = thisExpr; memberExpr->declRef = varDeclBase->getDefaultDeclRef(); @@ -8000,8 +7999,6 @@ namespace Slang foundCudaHostModifier = true; addModifier(func, m_astBuilder->create()); } - // - }; @@ -8069,7 +8066,7 @@ namespace Slang ctorToInvokeExpr->declRef = baseCtor->getDefaultDeclRef(); ctorToInvokeExpr->name = baseCtor->getName(); ctorToInvokeExpr->loc = baseCtor->loc; - ctorToInvokeExpr->type = baseCtor->returnType.type; + ctorToInvokeExpr->type = m_astBuilder->getFuncType(ArrayView(), baseCtor->returnType.type); auto invoke = m_astBuilder->create(); invoke->functionExpr = ctorToInvokeExpr; From d948c757ca739d08c376f9e34a5bfb96daa01153 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:26:27 -0400 Subject: [PATCH 042/100] allow `{}` inside `__init()` --- source/slang/slang-check-conversion.cpp | 2 +- source/slang/slang-check-decl.cpp | 240 +++++++++--------- source/slang/slang-check-impl.h | 9 +- source/slang/slang-constructor-utility.cpp | 52 +++- .../default-init-list-2.slang | 40 +++ 5 files changed, 211 insertions(+), 132 deletions(-) create mode 100644 tests/language-feature/initializer-lists/default-init-list-2.slang diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 6b896f0a93..cabb01cff7 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -480,7 +480,7 @@ namespace Slang { if (outToExpr) { - *outToExpr = constructZeroInitListFunc(this, toStructDecl, toType); + *outToExpr = constructZeroInitListFunc(this, toStructDecl, toType, ConstructZeroInitListOptions::CheckToAvoidRecursion); (*outToExpr)->loc = fromInitializerListExpr->loc; } return true; diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 9194b764a1..334e568ab0 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -8162,114 +8162,105 @@ namespace Slang if (destroyedDefaultCtor) { structDecl->members.remove(structDeclInfo.m_defaultCtor); - if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) - structDecl->members.remove(zeroInitListFunc); - structDecl->invalidateMemberDictionary(); structDecl->buildMemberDictionary(); - } } - // Only generate '$ZeroInit' if synthisized `__init()` exists - if (!destroyedDefaultCtor) + if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) { - if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) - { - SLANG_ASSERT(zeroInitListFunc->getParameters().getCount() == 0); - SLANG_ASSERT(zeroInitListFunc->findModifier()); - - SLANG_ASSERT(as(zeroInitListFunc->body)); - auto block = as(zeroInitListFunc->body); - SLANG_ASSERT(as(block->body)); - auto seqStmt = as(block->body); - - bool foundCudaHostModifier = false; - - auto defaultConstructExpr = m_astBuilder->create(); - defaultConstructExpr->type = structDeclType; - defaultConstructExpr->loc = seqStmt->loc; - - auto structVarDecl = m_astBuilder->create(); - addModifier(structVarDecl, m_astBuilder->create()); - structVarDecl->type = TypeExp(structDeclType); - structVarDecl->initExpr = defaultConstructExpr; - structVarDecl->parentDecl = zeroInitListFunc; - structVarDecl->loc = seqStmt->loc; - ensureDecl(structVarDecl, DeclCheckState::DefaultConstructorReadyForUse); - - auto structVarDeclExpr = m_astBuilder->create(); - structVarDeclExpr->declRef = structVarDecl->getDefaultDeclRef(); - structVarDeclExpr->name = structVarDecl->getName(); - structVarDeclExpr->loc = structVarDecl->loc; - structVarDeclExpr->type = GetTypeForDeclRef(structVarDecl, structVarDecl->loc); - structVarDeclExpr->type.isLeftValue = true; - structVarDeclExpr->scope = block->scopeDecl->ownedScope; - - auto structAssignExpr = m_astBuilder->create(); - structAssignExpr->left = structVarDeclExpr; - structAssignExpr->right = defaultConstructExpr; - auto structAssignExprStmt = m_astBuilder->create(); - structAssignExprStmt->expression = structAssignExpr; - structAssignExprStmt->loc = seqStmt->loc; - seqStmt->stmts.add(structAssignExprStmt); - - // Assign $ZeroInit of inheritanceDecl - if (baseStructInfo) - { - if (auto baseStructDecl = as(baseStructInfo->m_inheritanceBaseDecl)) - { - Expr* zeroInitFunc = constructZeroInitListFunc(this, baseStructDecl, baseStructInfo->m_inheritanceDecl->base.type); - auto assign = m_astBuilder->create(); - assign->left = coerce(CoercionSite::Initializer, zeroInitFunc->type, structVarDeclExpr); - assign->right = zeroInitFunc; - auto stmt = m_astBuilder->create(); - stmt->expression = assign; - stmt->loc = seqStmt->loc; - seqStmt->stmts.add(stmt); - } - } + SLANG_ASSERT(zeroInitListFunc->getParameters().getCount() == 0); + SLANG_ASSERT(zeroInitListFunc->findModifier()); - // Assign initExpr to all members - for (auto memberRef : membersOfStructDeclInstance) - { - auto member = memberRef.getDecl(); - auto initExpr = member->initExpr; - if (!initExpr) - continue; + SLANG_ASSERT(as(zeroInitListFunc->body)); + auto block = as(zeroInitListFunc->body); + SLANG_ASSERT(as(block->body)); + auto seqStmt = as(block->body); - MemberExpr* memberExpr = m_astBuilder->create(); - memberExpr->baseExpression = structVarDeclExpr; - memberExpr->declRef = member->getDefaultDeclRef(); - memberExpr->scope = zeroInitListFunc->ownedScope; - memberExpr->loc = member->loc; - memberExpr->name = member->getName(); - memberExpr->type = GetTypeForDeclRef(member, member->loc); - auto checkedMemberVarExpr = CheckTerm(memberExpr); - if (!checkedMemberVarExpr->type.isLeftValue) - continue; + bool foundCudaHostModifier = false; + auto defaultConstructExpr = m_astBuilder->create(); + defaultConstructExpr->type = structDeclType; + defaultConstructExpr->loc = seqStmt->loc; + + auto structVarDecl = m_astBuilder->create(); + addModifier(structVarDecl, m_astBuilder->create()); + structVarDecl->type = TypeExp(structDeclType); + structVarDecl->initExpr = defaultConstructExpr; + structVarDecl->parentDecl = zeroInitListFunc; + structVarDecl->loc = seqStmt->loc; + ensureDecl(structVarDecl, DeclCheckState::DefaultConstructorReadyForUse); + + auto structVarDeclExpr = m_astBuilder->create(); + structVarDeclExpr->declRef = structVarDecl->getDefaultDeclRef(); + structVarDeclExpr->name = structVarDecl->getName(); + structVarDeclExpr->loc = structVarDecl->loc; + structVarDeclExpr->type = GetTypeForDeclRef(structVarDecl, structVarDecl->loc); + structVarDeclExpr->type.isLeftValue = true; + structVarDeclExpr->scope = block->scopeDecl->ownedScope; + + auto structAssignExpr = m_astBuilder->create(); + structAssignExpr->left = structVarDeclExpr; + structAssignExpr->right = defaultConstructExpr; + auto structAssignExprStmt = m_astBuilder->create(); + structAssignExprStmt->expression = structAssignExpr; + structAssignExprStmt->loc = seqStmt->loc; + seqStmt->stmts.add(structAssignExprStmt); + + // Assign $ZeroInit of inheritanceDecl + if (baseStructInfo) + { + if (auto baseStructDecl = as(baseStructInfo->m_inheritanceBaseDecl)) + { + Expr* zeroInitFunc = constructZeroInitListFunc(this, baseStructDecl, baseStructInfo->m_inheritanceDecl->base.type, ConstructZeroInitListOptions::PreferZeroInitFunc); auto assign = m_astBuilder->create(); - assign->left = checkedMemberVarExpr; - assign->right = initExpr; - assign->loc = checkedMemberVarExpr->loc; - + assign->left = coerce(CoercionSite::Initializer, zeroInitFunc->type, structVarDeclExpr); + assign->right = zeroInitFunc; auto stmt = m_astBuilder->create(); stmt->expression = assign; - stmt->loc = assign->loc; - - addCudaHostModifierIfRequired(zeroInitListFunc, member, foundCudaHostModifier); + stmt->loc = seqStmt->loc; seqStmt->stmts.add(stmt); } + } - auto returnStmt = m_astBuilder->create(); - returnStmt->loc = structVarDeclExpr->loc; - returnStmt->expression = structVarDeclExpr; + // Assign initExpr to all members + for (auto memberRef : membersOfStructDeclInstance) + { + auto member = memberRef.getDecl(); + auto initExpr = member->initExpr; + if (!initExpr) + continue; + + MemberExpr* memberExpr = m_astBuilder->create(); + memberExpr->baseExpression = structVarDeclExpr; + memberExpr->declRef = member->getDefaultDeclRef(); + memberExpr->scope = zeroInitListFunc->ownedScope; + memberExpr->loc = member->loc; + memberExpr->name = member->getName(); + memberExpr->type = GetTypeForDeclRef(member, member->loc); + auto checkedMemberVarExpr = CheckTerm(memberExpr); + if (!checkedMemberVarExpr->type.isLeftValue) + continue; - seqStmt->stmts.add(returnStmt); + auto assign = m_astBuilder->create(); + assign->left = checkedMemberVarExpr; + assign->right = initExpr; + assign->loc = checkedMemberVarExpr->loc; + + auto stmt = m_astBuilder->create(); + stmt->expression = assign; + stmt->loc = assign->loc; + + addCudaHostModifierIfRequired(zeroInitListFunc, member, foundCudaHostModifier); + seqStmt->stmts.add(stmt); } - } + auto returnStmt = m_astBuilder->create(); + returnStmt->loc = structVarDeclExpr->loc; + returnStmt->expression = structVarDeclExpr; + + seqStmt->stmts.add(returnStmt); + } } void SemanticsDeclHeaderVisitor::cloneModifiers(Decl* dest, Decl* src) @@ -10535,44 +10526,51 @@ namespace Slang void SemanticsDeclAttributesVisitor::visitStructDecl(StructDecl* structDecl) { - // Add an empty default-Ctor and $ZeroInit if missing. + // Add an empty default-ctor if missing a real default-ctor. ConstructorDecl* defaultCtor = nullptr; List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); if (!defaultCtor) { defaultCtor = _createCtor(this, m_astBuilder, structDecl, {}, getDeclVisibility(structDecl)); ctorList.add(defaultCtor); + } - // $ZeroInit is a synthisized static-function only used if a user does not define a - // default ctor. Use of $ZeroInit is only for `{}` to avoid hacks. - auto zeroInitFunc = m_astBuilder->create(); - auto ctorName = getName("$ZeroInit"); - zeroInitFunc->ownedScope = m_astBuilder->create(); - zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; - zeroInitFunc->ownedScope->parent = getScope(structDecl); - zeroInitFunc->parentDecl = structDecl; - zeroInitFunc->loc = structDecl->loc; - zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; - zeroInitFunc->nameAndLoc.name = ctorName; - zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; - zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); - auto body = m_astBuilder->create(); - body->scopeDecl = m_astBuilder->create(); - body->scopeDecl->ownedScope = m_astBuilder->create(); - body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); - body->scopeDecl->parentDecl = zeroInitFunc; - body->scopeDecl->loc = zeroInitFunc->loc; - body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; - body->closingSourceLoc = zeroInitFunc->closingSourceLoc; - zeroInitFunc->body = body; - body->body = m_astBuilder->create(); - - addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); - addModifier(zeroInitFunc, m_astBuilder->create()); - addModifier(zeroInitFunc, m_astBuilder->create()); - addModifier(zeroInitFunc, m_astBuilder->create()); - addModifier(zeroInitFunc, m_astBuilder->create()); - structDecl->addMember(zeroInitFunc); + { + if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getCount() != 0) + { + // $ZeroInit is a synthisized static-function only used In 2 cases: + // 1. if `{}` is used inside a `__init()` + // 2. if `{}` is used and a user has a 'synthisized __init()` + // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. + auto zeroInitFunc = m_astBuilder->create(); + auto ctorName = getName("$ZeroInit"); + zeroInitFunc->ownedScope = m_astBuilder->create(); + zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; + zeroInitFunc->ownedScope->parent = getScope(structDecl); + zeroInitFunc->parentDecl = structDecl; + zeroInitFunc->loc = structDecl->loc; + zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; + zeroInitFunc->nameAndLoc.name = ctorName; + zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; + zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); + auto body = m_astBuilder->create(); + body->scopeDecl = m_astBuilder->create(); + body->scopeDecl->ownedScope = m_astBuilder->create(); + body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); + body->scopeDecl->parentDecl = zeroInitFunc; + body->scopeDecl->loc = zeroInitFunc->loc; + body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; + body->closingSourceLoc = zeroInitFunc->closingSourceLoc; + zeroInitFunc->body = body; + body->body = m_astBuilder->create(); + + addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); + addModifier(zeroInitFunc, m_astBuilder->create()); + addModifier(zeroInitFunc, m_astBuilder->create()); + addModifier(zeroInitFunc, m_astBuilder->create()); + addModifier(zeroInitFunc, m_astBuilder->create()); + structDecl->addMember(zeroInitFunc); + } } // Add an empty constructor for all combinations of visibility and access diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 31d6f4ae58..fdf94ddcec 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -2954,7 +2954,14 @@ namespace Slang bool DiagnoseIsAllowedInitExpr(VarDeclBase* varDecl, DiagnosticSink* sink); bool isDefaultInitializable(Type* varDeclType, VarDeclBase* associatedDecl); Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, TypeExp varDeclType, VarDeclBase* decl); - Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType); + + enum class ConstructZeroInitListOptions : UInt + { + None = 0 << 0, + PreferZeroInitFunc = 1 << 0, + CheckToAvoidRecursion = 1 << 2, + }; + Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructZeroInitListOptions options); FuncDecl* findZeroInitListFunc(StructDecl* structDecl); DeclRefBase* _getDeclRefFromVal(Val* val); diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index e8f3c1dc09..6a7cf4ecd5 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -158,10 +158,51 @@ namespace Slang return nullptr; } - Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType) + Expr* _constructZeroInitListFuncMakeDefaultCtorInvoke(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructorDecl* defaultCtor) + { + auto* invoke = visitor->getASTBuilder()->create(); + auto member = visitor->getASTBuilder()->getMemberDeclRef(structDecl->getDefaultDeclRef(), defaultCtor); + invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->loc, nullptr); + invoke->type = structDeclType; + return invoke; + } + Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructZeroInitListOptions options) { SLANG_ASSERT(structDecl); + // 1. Prefer non-synth default-ctor + // * Skip this option if `ConstructZeroInitListOptions::PreferZeroInitFunc` is true + // * Skip this option if `ConstructZeroInitListOptions::CheckToAvoidRecursion` detects recursion + // * Only user-defined ctor will try and have recursion of `{}` + // 2. Prefer $ZeroInit + // 3. Prefer any default-ctor + // 4. Use `DefaultConstructExpr` + + auto defaultCtor = _getDefaultCtor(structDecl); + if(defaultCtor + && !defaultCtor->containsOption(ConstructorTags::Synthesized) + && !((UInt)options & (UInt)ConstructZeroInitListOptions::PreferZeroInitFunc)) + { + bool canCreateCtor = true; + if(((UInt)options & (UInt)ConstructZeroInitListOptions::CheckToAvoidRecursion)) + { + auto callingScope = visitor->getOuterScope(); + if (callingScope) + { + do + { + if (callingScope->containerDecl == defaultCtor) + { + canCreateCtor = false; + break; + } + } while (callingScope = callingScope->parent); + } + } + if(canCreateCtor) + return _constructZeroInitListFuncMakeDefaultCtorInvoke(visitor, structDecl, structDeclType, defaultCtor); + } + // Try to get $ZeroInit if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) { @@ -174,14 +215,7 @@ namespace Slang // Try to get default-ctor if (auto defaultCtor = _getDefaultCtor(structDecl)) - { - auto* invoke = visitor->getASTBuilder()->create(); - auto member = visitor->getASTBuilder()->getMemberDeclRef(structDecl->getDefaultDeclRef(), defaultCtor); - invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->loc, nullptr); - invoke->type = structDeclType; - return invoke; - } - + return _constructZeroInitListFuncMakeDefaultCtorInvoke(visitor, structDecl, structDeclType, defaultCtor); // return DefaultConstructExpr auto* defaultCall = visitor->getASTBuilder()->create(); diff --git a/tests/language-feature/initializer-lists/default-init-list-2.slang b/tests/language-feature/initializer-lists/default-init-list-2.slang new file mode 100644 index 0000000000..b45e1d64ec --- /dev/null +++ b/tests/language-feature/initializer-lists/default-init-list-2.slang @@ -0,0 +1,40 @@ +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +public struct Test +{ +//CHECK: = 5 + public uint a; +//CHECK: = 0 + public uint b; + __init() + { + // This code will do 2 things: + // 1. call `$ZeroInit()` + // 2. assign `a = 5` + this = {}; + a = 5; + } +}; + +Test getDefault() +{ + Test test = {}; + return test; +} + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test test = getDefault(); + +//BUF: 1 + outputBuffer[0] = (true + && test.a == 5 + && test.b == 0 + ) ? 1 : 0 + ; +} \ No newline at end of file From cd1a46c9d93cdf7c6d6b3c7f39fd16c618ffa3db Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:34:18 -0400 Subject: [PATCH 043/100] fix compile error --- source/slang/slang-constructor-utility.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index 6a7cf4ecd5..e3fa94df4e 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -178,6 +178,7 @@ namespace Slang // 3. Prefer any default-ctor // 4. Use `DefaultConstructExpr` + // 1. auto defaultCtor = _getDefaultCtor(structDecl); if(defaultCtor && !defaultCtor->containsOption(ConstructorTags::Synthesized) @@ -203,7 +204,7 @@ namespace Slang return _constructZeroInitListFuncMakeDefaultCtorInvoke(visitor, structDecl, structDeclType, defaultCtor); } - // Try to get $ZeroInit + // 2. if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) { auto* invoke = visitor->getASTBuilder()->create(); @@ -213,11 +214,11 @@ namespace Slang return invoke; } - // Try to get default-ctor - if (auto defaultCtor = _getDefaultCtor(structDecl)) + // 3. + if (defaultCtor) return _constructZeroInitListFuncMakeDefaultCtorInvoke(visitor, structDecl, structDeclType, defaultCtor); - // return DefaultConstructExpr + // 4. auto* defaultCall = visitor->getASTBuilder()->create(); defaultCall->type = QualType(structDeclType); return defaultCall; From 4403ede74c0d6fad3a2e8c562b3a6638b3372815 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:44:27 -0400 Subject: [PATCH 044/100] fix another warning --- source/slang/slang-constructor-utility.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index e3fa94df4e..c1672e7f47 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -188,16 +188,14 @@ namespace Slang if(((UInt)options & (UInt)ConstructZeroInitListOptions::CheckToAvoidRecursion)) { auto callingScope = visitor->getOuterScope(); - if (callingScope) + while (callingScope) { - do + if (callingScope->containerDecl == defaultCtor) { - if (callingScope->containerDecl == defaultCtor) - { - canCreateCtor = false; - break; - } - } while (callingScope = callingScope->parent); + canCreateCtor = false; + break; + } + callingScope = callingScope->parent; } } if(canCreateCtor) From 99088c3e54197936660e560527856c167947dc3e Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 28 Aug 2024 18:37:00 -0400 Subject: [PATCH 045/100] auto-infer generic from the base-struct type with `constructZeroInitListFunc`; fix cudaHostModfiier assignment --- source/slang/slang-check-conversion.cpp | 2 +- source/slang/slang-check-decl.cpp | 4 ++-- source/slang/slang-constructor-utility.cpp | 12 +++++++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index cabb01cff7..05ba77e43d 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -568,7 +568,7 @@ namespace Slang constructorExpr->arguments.addRange(coercedArgs); constructorExpr->type = toType; - *outToExpr = CheckInvokeExprWithCheckedOperands(constructorExpr);//ResolveInvoke(constructorExpr); + *outToExpr = CheckInvokeExprWithCheckedOperands(constructorExpr); } return true; } diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 334e568ab0..9039c5ca6e 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -8227,6 +8227,8 @@ namespace Slang for (auto memberRef : membersOfStructDeclInstance) { auto member = memberRef.getDecl(); + addCudaHostModifierIfRequired(zeroInitListFunc, member, foundCudaHostModifier); + auto initExpr = member->initExpr; if (!initExpr) continue; @@ -8250,8 +8252,6 @@ namespace Slang auto stmt = m_astBuilder->create(); stmt->expression = assign; stmt->loc = assign->loc; - - addCudaHostModifierIfRequired(zeroInitListFunc, member, foundCudaHostModifier); seqStmt->stmts.add(stmt); } diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index c1672e7f47..ae07c30264 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -163,7 +163,7 @@ namespace Slang auto* invoke = visitor->getASTBuilder()->create(); auto member = visitor->getASTBuilder()->getMemberDeclRef(structDecl->getDefaultDeclRef(), defaultCtor); invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->loc, nullptr); - invoke->type = structDeclType; + invoke->type = visitor->getASTBuilder()->getFuncType(ArrayView(), structDeclType); return invoke; } Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructZeroInitListOptions options) @@ -206,9 +206,15 @@ namespace Slang if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) { auto* invoke = visitor->getASTBuilder()->create(); - auto member = visitor->getASTBuilder()->getMemberDeclRef(structDecl->getDefaultDeclRef(), zeroInitListFunc); + DeclRef member; + auto declRefType = as(structDeclType); + if(declRefType && as(declRefType->getDeclRefBase())) + member = visitor->getASTBuilder()->getMemberDeclRef(as(declRefType->getDeclRefBase()), zeroInitListFunc); + else + member = visitor->getASTBuilder()->getMemberDeclRef(structDecl, zeroInitListFunc); + invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, zeroInitListFunc->loc, nullptr); - invoke->type = structDeclType; + invoke->type = visitor->getASTBuilder()->getFuncType(ArrayView(), structDeclType); return invoke; } From 24f8c45d1175afccc1d9f53398903546e9fde52d Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 28 Aug 2024 18:41:52 -0400 Subject: [PATCH 046/100] fix a test --- tools/slang-unit-test/unit-test-decl-tree-reflection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 9c5fcf07c3..a6121469ff 100644 --- a/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp +++ b/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp @@ -112,10 +112,10 @@ SLANG_UNIT_TEST(declTreeReflection) SLANG_CHECK(moduleDeclReflection->getKind() == slang::DeclReflection::Kind::Module); SLANG_CHECK(moduleDeclReflection->getChildrenCount() == 8); - // First declaration should be a struct with 1 variable and 1 constructor (memberwise ctor) + // First declaration should be a struct with 1 variable, 1 constructor (memberwise ctor), 1 funcDecl ($ZeroInit) auto firstDecl = moduleDeclReflection->getChild(0); SLANG_CHECK(firstDecl->getKind() == slang::DeclReflection::Kind::Struct); - SLANG_CHECK(firstDecl->getChildrenCount() == 2); + SLANG_CHECK(firstDecl->getChildrenCount() == 3); { slang::TypeReflection* type = firstDecl->getType(); From 25138e046ab68f5dfe8dbd7383e9ab7b4c6b1859 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 28 Aug 2024 21:03:34 -0400 Subject: [PATCH 047/100] fix cyclic ref error for DefaultConstruct --- source/slang/slang-ir-insts.h | 1 + source/slang/slang-ir.cpp | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 3236bb2e6d..ef5108e975 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -3840,6 +3840,7 @@ struct IRBuilder /// If `fallback` is true, will emit `DefaultConstruct` inst on unknown types. /// Otherwise, returns nullptr if we can't materialize the inst. IRInst* emitDefaultConstruct(IRType* type, bool fallback = true); + IRInst* _emitDefaultConstruct(IRType* type, bool fallback, HashSet visitedTypes); /// Emits a raw `DefaultConstruct` opcode without attempting to fold/materialize /// the inst. diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 0b0a426175..8b8ced9f3b 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -3736,8 +3736,11 @@ namespace Slang return emitIntrinsicInst(type, kIROp_DefaultConstruct, 0, nullptr); } - IRInst* IRBuilder::emitDefaultConstruct(IRType* type, bool fallback) + IRInst* IRBuilder::_emitDefaultConstruct(IRType* type, bool fallback, HashSet visitedTypes) { + if (visitedTypes.contains(type)) + return emitUndefined(type); + visitedTypes.add(type); IRType* actualType = type; for (;;) { @@ -3784,7 +3787,7 @@ namespace Slang return getNullPtrValue(type); case kIROp_OptionalType: { - auto inner = emitDefaultConstruct(as(actualType)->getValueType(), fallback); + auto inner = _emitDefaultConstruct(as(actualType)->getValueType(), fallback, visitedTypes); if (!inner) return nullptr; return emitMakeOptionalNone(type, inner); @@ -3798,7 +3801,7 @@ namespace Slang auto operand = tupleType->getOperand(i); if (as(operand)) break; - auto inner = emitDefaultConstruct((IRType*)operand, fallback); + auto inner = _emitDefaultConstruct((IRType*)operand, fallback, visitedTypes); if (!inner) return nullptr; elements.add(inner); @@ -3812,7 +3815,7 @@ namespace Slang for (auto field : structType->getFields()) { auto fieldType = field->getFieldType(); - auto inner = emitDefaultConstruct(fieldType, fallback); + auto inner = _emitDefaultConstruct(fieldType, fallback, visitedTypes); if (!inner) return nullptr; elements.add(inner); @@ -3824,7 +3827,7 @@ namespace Slang auto arrayType = as(actualType); if (auto count = as(arrayType->getElementCount())) { - auto element = emitDefaultConstruct(arrayType->getElementType(), fallback); + auto element = _emitDefaultConstruct(arrayType->getElementType(), fallback, visitedTypes); if (!element) return nullptr; List elements; @@ -3841,14 +3844,14 @@ namespace Slang } case kIROp_VectorType: { - auto inner = emitDefaultConstruct(as(actualType)->getElementType(), fallback); + auto inner = _emitDefaultConstruct(as(actualType)->getElementType(), fallback, visitedTypes); if (!inner) return nullptr; return emitIntrinsicInst(type, kIROp_MakeVectorFromScalar, 1, &inner); } case kIROp_MatrixType: { - auto inner = emitDefaultConstruct(as(actualType)->getElementType(), fallback); + auto inner = _emitDefaultConstruct(as(actualType)->getElementType(), fallback, visitedTypes); if (!inner) return nullptr; return emitIntrinsicInst(type, kIROp_MakeMatrixFromScalar, 1, &inner); @@ -3862,7 +3865,10 @@ namespace Slang } return nullptr; } - + IRInst* IRBuilder::emitDefaultConstruct(IRType* type, bool fallback) + { + return _emitDefaultConstruct(type, fallback, {}); + } IRInst* IRBuilder::emitEmbeddedDXIL(ISlangBlob *blob) { IRInst* args[] = { getBlobValue(blob) }; From 93af3db3e8c5074fd981c3412d9c486766efc804 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 28 Aug 2024 21:10:50 -0400 Subject: [PATCH 048/100] dont make reg func a `()` wrapped func --- source/slang/slang-constructor-utility.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index ae07c30264..e283e20f6c 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -214,7 +214,7 @@ namespace Slang member = visitor->getASTBuilder()->getMemberDeclRef(structDecl, zeroInitListFunc); invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, zeroInitListFunc->loc, nullptr); - invoke->type = visitor->getASTBuilder()->getFuncType(ArrayView(), structDeclType); + invoke->type = structDeclType; return invoke; } From c026b07595b41ce94e67f1a2063e17825aa1e049 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 28 Aug 2024 21:37:18 -0400 Subject: [PATCH 049/100] fix visibility and type issue --- source/slang/slang-check-decl.cpp | 2 +- source/slang/slang-constructor-utility.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 9039c5ca6e..558363a406 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -10567,7 +10567,7 @@ namespace Slang addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); addModifier(zeroInitFunc, m_astBuilder->create()); addModifier(zeroInitFunc, m_astBuilder->create()); - addModifier(zeroInitFunc, m_astBuilder->create()); + addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); addModifier(zeroInitFunc, m_astBuilder->create()); structDecl->addMember(zeroInitFunc); } diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index e283e20f6c..b1731c0c20 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -158,12 +158,12 @@ namespace Slang return nullptr; } - Expr* _constructZeroInitListFuncMakeDefaultCtorInvoke(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructorDecl* defaultCtor) + Expr* _constructZeroInitListFuncMakeDefaultCtor(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructorDecl* defaultCtor) { auto* invoke = visitor->getASTBuilder()->create(); auto member = visitor->getASTBuilder()->getMemberDeclRef(structDecl->getDefaultDeclRef(), defaultCtor); invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->loc, nullptr); - invoke->type = visitor->getASTBuilder()->getFuncType(ArrayView(), structDeclType); + invoke->type = structDeclType; return invoke; } Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructZeroInitListOptions options) @@ -199,7 +199,7 @@ namespace Slang } } if(canCreateCtor) - return _constructZeroInitListFuncMakeDefaultCtorInvoke(visitor, structDecl, structDeclType, defaultCtor); + return _constructZeroInitListFuncMakeDefaultCtor(visitor, structDecl, structDeclType, defaultCtor); } // 2. @@ -220,7 +220,7 @@ namespace Slang // 3. if (defaultCtor) - return _constructZeroInitListFuncMakeDefaultCtorInvoke(visitor, structDecl, structDeclType, defaultCtor); + return _constructZeroInitListFuncMakeDefaultCtor(visitor, structDecl, structDeclType, defaultCtor); // 4. auto* defaultCall = visitor->getASTBuilder()->create(); From 915b0b86606b424bb801659d5100bc796ae98267 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:42:06 -0400 Subject: [PATCH 050/100] add defaults to syth'ed ctor's under special situations to allow c-style-partial-initializers --- source/slang/slang-check-conversion.cpp | 37 +--- source/slang/slang-check-decl.cpp | 160 +++++++++++------- source/slang/slang-check-impl.h | 13 ++ source/slang/slang-constructor-utility.cpp | 82 ++++++++- .../initializer-lists/partial-init-list.slang | 41 +++++ 5 files changed, 231 insertions(+), 102 deletions(-) create mode 100644 tests/language-feature/initializer-lists/partial-init-list.slang diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 05ba77e43d..8695bfd5f6 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -213,29 +213,6 @@ namespace Slang return nullptr; } - bool _allowCStyleInitList(List ctorList) - { - bool foundNonDefaultInit = false; - for (auto i : ctorList) - { - // Default ctor do not affect this logic. - if (i->getParameters().getCount() == 0) - continue; - - // Cannot contain user defined ctor which is a non default ctor - if (!i->containsOption(ConstructorTags::Synthesized)) - return false; - - // Cannot contain 2+ non-default init's, this is ambigious for a c-style init list: - // `MyStruct[3] tmp = {1,2, 1,2, 1,2};` - // if `__init(int, int)` and `__init(int)` were both defined we would have ambiguity. - if (foundNonDefaultInit) - return false; - foundNonDefaultInit = true; - } - return true; - } - bool SemanticsVisitor::_readAggregateValueFromInitializerList( Type* inToType, Expr** outToExpr, @@ -473,7 +450,7 @@ namespace Slang ensureDecl(toStructDecl, DeclCheckState::DefaultConstructorReadyForUse); List ctorList = _getCtorList(this->getASTBuilder(), this, toStructDecl, nullptr); - bool allowCStyleInitList = _allowCStyleInitList(ctorList); + bool allowCStyleInitList = checkIfCStyleStruct(this, toStructDecl); // Easy case of default constructor or equivalent if (argCount == 0) @@ -502,7 +479,7 @@ namespace Slang ioArgIndexCandidate = ioArgIndexMirror; ioArgIndex = ctorParamCount; - // if allowCStyleInitList, process any ctor which comes next. ioArgIndex may not be 0 + // if allowCStyleInitList, process any ctor which comes next using the most members possible. ioArgIndex may not be 0. // if !allowCStyleInitList, process any ctor that exactly matched our argument count. ioArgIndex must start at 0. if (!allowCStyleInitList && ctorParamCount != Index(argCount)) continue; @@ -513,6 +490,10 @@ namespace Slang for (auto index = coercedArgs.getCount(); index < parametersCount; index++) { + // If we ran out of elements (and are using a c-style-constructor, end early. + if (ioArgIndexCandidate > fromInitializerListExpr->args.getCount()) + break; + auto ctorParam = parameters[index]; auto paramType = ctorParam.getDecl()->type.type; for (auto i : getMembersOfType(m_astBuilder, toStructDeclRef, MemberFilterStyle::Instance)) @@ -532,7 +513,7 @@ namespace Slang break; } - if (maybeArgList.getCount() != ctorParamCount) + if (!allowCStyleInitList && maybeArgList.getCount() != ctorParamCount) continue; // Skip non-visible constructors. @@ -1053,9 +1034,7 @@ namespace Slang } if (outToExpr) { - auto* defaultExpr = getASTBuilder()->create(); - defaultExpr->type = QualType(toType); - *outToExpr = defaultExpr; + *outToExpr = createDefaultConstructExprForType(getASTBuilder(), QualType(toType), {}); } return true; } diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 558363a406..024fa6bb86 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1824,11 +1824,27 @@ namespace Slang addModifier(func, m_astBuilder->create()); } + + struct CreateCtorArg + { + VarDeclBase* m_argToCopy; + Expr* m_initExpr = nullptr; + + // Do not add initExpr to list since other-wise we will have more than 1 'default ctor' + // which Slang disallows. + static void addArgToList(List& argList, VarDeclBase* argToCopy, Expr* initExpr) + { + if(argList.getCount() == 0) + argList.add({ argToCopy, nullptr }); + else + argList.add({ argToCopy, initExpr }); + } + }; static ConstructorDecl* _createCtor( SemanticsDeclVisitorBase* visitor, ASTBuilder* m_astBuilder, AggTypeDecl* decl, - List&& argList, + List&& argList, DeclVisibility visibility) { auto ctor = m_astBuilder->create(); @@ -1864,7 +1880,8 @@ namespace Slang for (auto arg : argList) { auto param = m_astBuilder->create(); - param->type = (TypeExp)arg->type; + param->type = (TypeExp)arg.m_argToCopy->type; + param->initExpr = arg.m_initExpr; param->parentDecl = ctor; param->loc = ctor->loc; ctor->members.add(param); @@ -7719,7 +7736,9 @@ namespace Slang static bool _doesCtorExpectInitializerListUsage(ConstructorDecl* ctor) { - return ctor->containsOption(ConstructorTags::Synthesized) && ctor->getParameters().getCount() != 0 && !allParamHaveInitExpr(ctor); + return ctor->containsOption(ConstructorTags::Synthesized) + && ctor->getParameters().getCount() != 0 + && !allParamHaveInitExpr(ctor); } template @@ -8179,9 +8198,7 @@ namespace Slang bool foundCudaHostModifier = false; - auto defaultConstructExpr = m_astBuilder->create(); - defaultConstructExpr->type = structDeclType; - defaultConstructExpr->loc = seqStmt->loc; + auto defaultConstructExpr = createDefaultConstructExprForType(m_astBuilder, structDeclType, seqStmt->loc); auto structVarDecl = m_astBuilder->create(); addModifier(structVarDecl, m_astBuilder->create()); @@ -10478,7 +10495,7 @@ namespace Slang static ConstructorDecl* _tryToGenerateCtorWithArgList( SemanticsDeclVisitorBase* visitor, ASTBuilder* astBuilder, - List&& args, + List&& args, List& existingCtorList, StructDecl* structDecl, DeclVisibility visibility) @@ -10502,7 +10519,7 @@ namespace Slang bool equalCtor = true; for(Index i = 0; i < newCtorArgsLength; i++) { - auto newCtorArg = args[i]; + auto newCtorArg = args[i].m_argToCopy; auto existingCtorArg = existingCtorArgs[i]; if (visitor->getConversionCost(newCtorArg->getType(), existingCtorArg->getType()) == kConversionCost_Impossible) { @@ -10535,52 +10552,52 @@ namespace Slang ctorList.add(defaultCtor); } - { - if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getCount() != 0) - { - // $ZeroInit is a synthisized static-function only used In 2 cases: - // 1. if `{}` is used inside a `__init()` - // 2. if `{}` is used and a user has a 'synthisized __init()` - // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. - auto zeroInitFunc = m_astBuilder->create(); - auto ctorName = getName("$ZeroInit"); - zeroInitFunc->ownedScope = m_astBuilder->create(); - zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; - zeroInitFunc->ownedScope->parent = getScope(structDecl); - zeroInitFunc->parentDecl = structDecl; - zeroInitFunc->loc = structDecl->loc; - zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; - zeroInitFunc->nameAndLoc.name = ctorName; - zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; - zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); - auto body = m_astBuilder->create(); - body->scopeDecl = m_astBuilder->create(); - body->scopeDecl->ownedScope = m_astBuilder->create(); - body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); - body->scopeDecl->parentDecl = zeroInitFunc; - body->scopeDecl->loc = zeroInitFunc->loc; - body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; - body->closingSourceLoc = zeroInitFunc->closingSourceLoc; - zeroInitFunc->body = body; - body->body = m_astBuilder->create(); - - addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); - addModifier(zeroInitFunc, m_astBuilder->create()); - addModifier(zeroInitFunc, m_astBuilder->create()); - addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); - addModifier(zeroInitFunc, m_astBuilder->create()); - structDecl->addMember(zeroInitFunc); - } - } + if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getCount() != 0) + { + // $ZeroInit is a synthisized static-function only used In 2 cases: + // 1. if `{}` is used inside a `__init()` + // 2. if `{}` is used and a user has a 'synthisized __init()` + // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. + auto zeroInitFunc = m_astBuilder->create(); + auto ctorName = getName("$ZeroInit"); + zeroInitFunc->ownedScope = m_astBuilder->create(); + zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; + zeroInitFunc->ownedScope->parent = getScope(structDecl); + zeroInitFunc->parentDecl = structDecl; + zeroInitFunc->loc = structDecl->loc; + zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; + zeroInitFunc->nameAndLoc.name = ctorName; + zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; + zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); + auto body = m_astBuilder->create(); + body->scopeDecl = m_astBuilder->create(); + body->scopeDecl->ownedScope = m_astBuilder->create(); + body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); + body->scopeDecl->parentDecl = zeroInitFunc; + body->scopeDecl->loc = zeroInitFunc->loc; + body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; + body->closingSourceLoc = zeroInitFunc->closingSourceLoc; + zeroInitFunc->body = body; + body->body = m_astBuilder->create(); + + addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); + addModifier(zeroInitFunc, m_astBuilder->create()); + addModifier(zeroInitFunc, m_astBuilder->create()); + addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); + addModifier(zeroInitFunc, m_astBuilder->create()); + structDecl->addMember(zeroInitFunc); + } + + bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); // Add an empty constructor for all combinations of visibility and access // which is possible: // 1. public constructor - usable *outside class scope* in a *different module* - List publicCtorArgs; + List publicCtorArgs; // 2. public-internal constructor - usable *outside class scope* in the *same module* - List publicInternalCtorArgs; + List publicInternalCtorArgs; // 3. public-private-internal constructor - usable *inside class scope* in the *same module* - List publicPrivateInternalCtorArgs; + List publicPrivateInternalCtorArgs; // Harvest parameters which map to the base type ctor. // Note: assumes 1 structDecl, N number inheritance decl @@ -10592,7 +10609,7 @@ namespace Slang auto baseStruct = as(declRefType->getDeclRef().getDecl()); if (!baseStruct) continue; - + DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; ConstructorDecl* ctorForPublic = nullptr; @@ -10620,20 +10637,29 @@ namespace Slang { for (auto i : ctorForPublic->getParameters()) { - publicCtorArgs.add(i); + Expr* initExpr = nullptr; + if (isCStyleStruct) + initExpr = createDefaultConstructExprForType(m_astBuilder, QualType(i->type), {}); + + CreateCtorArg::addArgToList(publicCtorArgs, i, initExpr); } for (auto i : ctorForInternal->getParameters()) { - publicInternalCtorArgs.add(i); - publicPrivateInternalCtorArgs.add(i); + Expr* initExpr = nullptr; + if (isCStyleStruct) + initExpr = createDefaultConstructExprForType(m_astBuilder, QualType(i->type), {}); + + CreateCtorArg::addArgToList(publicInternalCtorArgs, i, initExpr); + CreateCtorArg::addArgToList(publicPrivateInternalCtorArgs, i, initExpr); } } } + // If we have a internal field which is not default-initialized we cannot allow // a (1:1 element) ctor for public members (public member-wise ctor) to synthesize. // This principal also applies for private members and internal/public member-wise ctor synthisis. - DeclVisibility maxVisibilityToGenerateCtor = getDeclVisibility(structDecl); + DeclVisibility maxVisibilityCtorToGenerate = getDeclVisibility(structDecl); for(auto varDeclRef : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) { auto varDecl = varDeclRef.getDecl(); @@ -10643,25 +10669,28 @@ namespace Slang if (!getTypeForDeclRef(m_astBuilder, varDeclRef, varDeclRef.getLoc()).isLeftValue) continue; - auto declVisibility = getDeclVisibility(varDecl); + Expr* initExpr = nullptr; + if (isCStyleStruct) + initExpr = createDefaultConstructExprForType(m_astBuilder, QualType(varDecl->type), {}); + auto declVisibility = getDeclVisibility(varDecl); switch (declVisibility) { case DeclVisibility::Private: - publicPrivateInternalCtorArgs.add(varDecl); + CreateCtorArg::addArgToList(publicPrivateInternalCtorArgs, varDecl, initExpr); if(!varDecl->initExpr) - maxVisibilityToGenerateCtor = DeclVisibility::Private; + maxVisibilityCtorToGenerate = DeclVisibility::Private; break; case DeclVisibility::Internal: - publicPrivateInternalCtorArgs.add(varDecl); - publicInternalCtorArgs.add(varDecl); + CreateCtorArg::addArgToList(publicPrivateInternalCtorArgs, varDecl, initExpr); + CreateCtorArg::addArgToList(publicInternalCtorArgs, varDecl, initExpr); if (!varDecl->initExpr) - maxVisibilityToGenerateCtor = DeclVisibility::Internal; + maxVisibilityCtorToGenerate = DeclVisibility::Internal; break; case DeclVisibility::Public: - publicPrivateInternalCtorArgs.add(varDecl); - publicInternalCtorArgs.add(varDecl); - publicCtorArgs.add(varDecl); + CreateCtorArg::addArgToList(publicPrivateInternalCtorArgs, varDecl, initExpr); + CreateCtorArg::addArgToList(publicInternalCtorArgs, varDecl, initExpr); + CreateCtorArg::addArgToList(publicCtorArgs, varDecl, initExpr); break; default: // Unknown visibility @@ -10669,11 +10698,12 @@ namespace Slang break; } } - if (maxVisibilityToGenerateCtor >= DeclVisibility::Public) + + if (maxVisibilityCtorToGenerate >= DeclVisibility::Public) _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public); - if (maxVisibilityToGenerateCtor >= DeclVisibility::Internal) + if (maxVisibilityCtorToGenerate >= DeclVisibility::Internal) _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal); - if (maxVisibilityToGenerateCtor >= DeclVisibility::Private) + if (maxVisibilityCtorToGenerate >= DeclVisibility::Private) _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicPrivateInternalCtorArgs), ctorList, structDecl, DeclVisibility::Private); int backingWidth = 0; diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index fdf94ddcec..1620190aa5 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -712,6 +712,14 @@ namespace Slang m_mapTypePairToImplicitCastMethod[key] = candidate; } + void cacheIsCStyleStruct(StructDecl* structDecl, bool isCStyleStruct) + { + m_isCStyleStruct[structDecl] = isCStyleStruct; + } + bool* tryGetIsCStyleStructFromCache(StructDecl* structDecl) + { + return m_isCStyleStruct.tryGetValue(structDecl); + } private: /// Mapping from type declarations to the known extensiosn that apply to them Dictionary> m_mapTypeDeclToCandidateExtensions; @@ -831,6 +839,7 @@ namespace Slang Dictionary, InheritanceInfo> m_mapDeclRefToInheritanceInfo; Dictionary m_mapTypePairToSubtypeWitness; Dictionary m_mapTypePairToImplicitCastMethod; + Dictionary m_isCStyleStruct; }; /// Local/scoped state of the semantic-checking system @@ -2964,6 +2973,10 @@ namespace Slang Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructZeroInitListOptions options); FuncDecl* findZeroInitListFunc(StructDecl* structDecl); + bool checkIfCStyleStruct(SemanticsVisitor* visitor, StructDecl* decl); + + DefaultConstructExpr* createDefaultConstructExprForType(ASTBuilder* m_astBuilder, QualType type, SourceLoc loc); + DeclRefBase* _getDeclRefFromVal(Val* val); } diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index b1731c0c20..ab2b5045b0 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -3,6 +3,15 @@ namespace Slang { + + DefaultConstructExpr* createDefaultConstructExprForType(ASTBuilder* m_astBuilder, QualType type, SourceLoc loc) + { + auto defaultConstructExpr = m_astBuilder->create(); + defaultConstructExpr->type = type; + defaultConstructExpr->loc = loc; + return defaultConstructExpr; + } + ConstructorDecl* _getDefaultCtor(StructDecl* structDecl) { for (auto ctor : structDecl->getMembersOfType()) @@ -42,7 +51,9 @@ namespace Slang if (!ctor) return; ctorList.add(ctor); - if (ctor->members.getCount() != 0 && !allParamHaveInitExpr(ctor) || !defaultCtorOut) + if (ctor->members.getCount() != 0 + && !allParamHaveInitExpr(ctor) + || !defaultCtorOut) return; *defaultCtorOut = ctor; }; @@ -141,9 +152,7 @@ namespace Slang } else { - auto* defaultCall = visitor->getASTBuilder()->create(); - defaultCall->type = QualType(varDeclType.type); - return defaultCall; + return createDefaultConstructExprForType(visitor->getASTBuilder(), QualType(varDeclType.type), {}); } } @@ -223,9 +232,66 @@ namespace Slang return _constructZeroInitListFuncMakeDefaultCtor(visitor, structDecl, structDeclType, defaultCtor); // 4. - auto* defaultCall = visitor->getASTBuilder()->create(); - defaultCall->type = QualType(structDeclType); - return defaultCall; + return createDefaultConstructExprForType(visitor->getASTBuilder(), QualType(structDeclType), {}); } -} + bool checkIfCStyleStruct(SemanticsVisitor* visitor, StructDecl* structDecl) + { + // CStyleStruct follows the following rules: + // 1. Does not contain a non 'Synthesized' Ctor (excluding 'DefaultCtor') + // + // 2. Only contains 1 'non-default' ctor regardless of synthisis or not, else + // `__init(int, int)` and `__init(int)` would have ambiguity for + // c-style-initialization of `MyStruct[3] tmp = {1,2, 1,2, 1,2};` + // + // 3. Every `VarDeclBase*` member has the same visibility + + auto isCStyleStruct = visitor->getShared()->tryGetIsCStyleStructFromCache(structDecl); + + if (isCStyleStruct) + return *isCStyleStruct; + + // Add to IsCStyleStruct cache + auto ctorList = _getCtorList(visitor->getASTBuilder(), visitor, structDecl, nullptr); + int nonDefaultInitCount = 0; + for (auto i : ctorList) + { + // Default ctor is always fine + if (i->getParameters().getCount() == 0) + continue; + + // Cannot contain user defined ctor which is a non default ctor + if (!i->containsOption(ConstructorTags::Synthesized)) + { + visitor->getShared()->cacheIsCStyleStruct(structDecl, false); + return false; + } + + // Cannot contain 2+ non-default init's + nonDefaultInitCount++; + if (nonDefaultInitCount > 1) + { + visitor->getShared()->cacheIsCStyleStruct(structDecl, false); + return false; + } + } + + // We need this additional check if we did not resolve all ctor's based on visibility yet + if (!structDecl->isChecked(DeclCheckState::AttributesChecked)) + { + HashSet visibilities; + for (auto i : getMembersOfType(visitor->getASTBuilder(), structDecl, MemberFilterStyle::Instance)) + { + visibilities.add(getDeclVisibility(i.getDecl())); + if (visibilities.getCount() != 1) + { + visitor->getShared()->cacheIsCStyleStruct(structDecl, false); + return false; + } + } + } + + visitor->getShared()->cacheIsCStyleStruct(structDecl, true); + return true; + } +} diff --git a/tests/language-feature/initializer-lists/partial-init-list.slang b/tests/language-feature/initializer-lists/partial-init-list.slang new file mode 100644 index 0000000000..a63508d498 --- /dev/null +++ b/tests/language-feature/initializer-lists/partial-init-list.slang @@ -0,0 +1,41 @@ +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj + +//CHECK: computeMain + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +public struct Test +{ + public uint a; + public uint b; +}; + +Test getTest1() +{ + Test test = {1, 2}; + return test; +} +Test getTest2() +{ + Test test = {3}; + return test; +} + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test test1 = getTest1(); + Test test2 = getTest2(); + +//BUF: 1 + outputBuffer[0] = (true + && test1.a == 1 + && test1.b == 2 + + && test2.a == 3 + && test2.b == 0 + ) ? 1 : 0 + ; +} \ No newline at end of file From 31c1e464295366db9650e633c1986e7751cdf0da Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:46:30 -0400 Subject: [PATCH 051/100] fix warning --- source/slang/slang-check-conversion.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 8695bfd5f6..3fce19d4aa 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -490,8 +490,8 @@ namespace Slang for (auto index = coercedArgs.getCount(); index < parametersCount; index++) { - // If we ran out of elements (and are using a c-style-constructor, end early. - if (ioArgIndexCandidate > fromInitializerListExpr->args.getCount()) + // If we ran out of elements and allow using a c-style-partial-initialization-list-constructor, end early. + if ((Index)ioArgIndexCandidate > fromInitializerListExpr->args.getCount()) break; auto ctorParam = parameters[index]; From c2700559f6b2f76a6f8313d2478e2210987d02c0 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 29 Aug 2024 15:29:02 -0400 Subject: [PATCH 052/100] handle `shouldUseInitializerDirectly` differently to work better with 'partial-initializer-lists', disable incorrect warning (will need to look into it) --- source/slang/slang-check-conversion.cpp | 7 +++++-- .../initializer-lists/default-init-list-2.slang | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 3fce19d4aa..5f7919a61b 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -92,11 +92,14 @@ namespace Slang if(isEffectivelyScalarForInitializerLists(fromExpr->type)) return false; + if (toType->equals(fromExpr->type)) + return true; + // Once the above cases are handled, the main thing // we want to check for is whether a direct initialization // is possible (a type conversion exists). // - return canCoerce(toType, fromExpr->type, fromExpr); + return false; } bool SemanticsVisitor::_readValueFromInitializerList( @@ -490,7 +493,7 @@ namespace Slang for (auto index = coercedArgs.getCount(); index < parametersCount; index++) { - // If we ran out of elements and allow using a c-style-partial-initialization-list-constructor, end early. + // If we ran out of elements and allow using a c-style-partial-initialization-list, end early. if ((Index)ioArgIndexCandidate > fromInitializerListExpr->args.getCount()) break; diff --git a/tests/language-feature/initializer-lists/default-init-list-2.slang b/tests/language-feature/initializer-lists/default-init-list-2.slang index b45e1d64ec..64f2755bec 100644 --- a/tests/language-feature/initializer-lists/default-init-list-2.slang +++ b/tests/language-feature/initializer-lists/default-init-list-2.slang @@ -1,5 +1,8 @@ -//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj +// NOTE: 'warning of uninitialized values system' does not handle assignments to `this`. +// For example, `this = {};`. + +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute -Wno-41020 +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj -xslang -Wno-41020 //TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer RWStructuredBuffer outputBuffer; From de1bc55859e0f4c429dcfee0d35e7c0ea1a22771 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:28:43 -0400 Subject: [PATCH 053/100] test clean-up and additional test-case --- .../cstyle-init-list-2.slang | 41 +++++++++++++++++++ .../default-init-list-2.slang | 7 +--- 2 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 tests/language-feature/initializer-lists/cstyle-init-list-2.slang diff --git a/tests/language-feature/initializer-lists/cstyle-init-list-2.slang b/tests/language-feature/initializer-lists/cstyle-init-list-2.slang new file mode 100644 index 0000000000..f98c3bb59b --- /dev/null +++ b/tests/language-feature/initializer-lists/cstyle-init-list-2.slang @@ -0,0 +1,41 @@ +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj +//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF): -vk -shaderobj + +struct TestInner +{ + float4 a; +}; + +TestInner makeTestInner(float v) +{ + TestInner val; + val.a = (float4)v; + return val; +} + +struct Test +{ + float3 a; + float3 b; + TestInner c; +}; + + +//CHECK: computeMain + +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test test = { float3(1, 2, 3), (float3)2, makeTestInner(3) }; + +//BUF: 1 + outputBuffer[0] = true + && all(test.a == float3(1, 2, 3)) + && all(test.b == float3(2, 2, 2)) + && all(test.c.a == float4(3, 3, 3, 3)) + ; +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/default-init-list-2.slang b/tests/language-feature/initializer-lists/default-init-list-2.slang index 64f2755bec..b45e1d64ec 100644 --- a/tests/language-feature/initializer-lists/default-init-list-2.slang +++ b/tests/language-feature/initializer-lists/default-init-list-2.slang @@ -1,8 +1,5 @@ -// NOTE: 'warning of uninitialized values system' does not handle assignments to `this`. -// For example, `this = {};`. - -//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute -Wno-41020 -//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj -xslang -Wno-41020 +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj //TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer RWStructuredBuffer outputBuffer; From 4f6a3436619c56a84f8ece093863afb26a72c44e Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:17:44 -0400 Subject: [PATCH 054/100] remove overload logic added, replace with simple solution of proper lookup --- source/slang/slang-check-conversion.cpp | 25 +-- source/slang/slang-check-expr.cpp | 2 +- source/slang/slang-check-overload.cpp | 191 +++++------------- source/slang/slang-constructor-utility.cpp | 2 +- source/slang/slang-diagnostic-defs.h | 2 +- .../initializer-lists/cstyle-init-list.slang | 8 +- .../init-list-with-autodiff-attributes.slang | 41 ++++ 7 files changed, 113 insertions(+), 158 deletions(-) create mode 100644 tests/language-feature/initializer-lists/init-list-with-autodiff-attributes.slang diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 5f7919a61b..b492d1a502 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -537,22 +537,19 @@ namespace Slang for (auto i : maybeArgList) coercedArgs.add(i); - // We want lookup to resolve our init function as a generic using Slang's - // builtin 'lookup' logic. - // Note, we need to also ensure we can infer the generic based on the target type - auto ctorToInvoke = m_astBuilder->create(); - ctorToInvoke->scope = toStructDecl->ownedScope; - ctorToInvoke->name = getName(String(toStructDecl->getName()->text)); - ctorToInvoke->type = toType; - Expr* callee = CheckExpr(ctorToInvoke); - - InvokeExpr* constructorExpr = m_astBuilder->create(); - constructorExpr->loc = fromInitializerListExpr->loc; - constructorExpr->functionExpr = callee; + List argTypes; + for (auto i : coercedArgs) + argTypes.add(i->type); + + auto* varExpr = getASTBuilder()->create(); + varExpr->type = (QualType)getASTBuilder()->getTypeType(toType); + varExpr->declRef = isDeclRefTypeOf(toType); + auto* constructorExpr = getASTBuilder()->create(); + constructorExpr->functionExpr = varExpr; constructorExpr->arguments.addRange(coercedArgs); - constructorExpr->type = toType; + auto resolvedConstructorExpr = CheckExpr(constructorExpr); - *outToExpr = CheckInvokeExprWithCheckedOperands(constructorExpr); + *outToExpr = resolvedConstructorExpr; } return true; } diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 32305dfdd5..05e3502d1f 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -2639,7 +2639,7 @@ namespace Slang if (auto varExpr = as(expr->functionExpr)) { - if ((varExpr->name->text == "&&") || (varExpr->name->text == "||")) + if (varExpr->name && (varExpr->name->text == "&&" || varExpr->name->text == "||")) { // We only use short-circuiting in scalar input, will fall back // to non-short-circuiting in vector input. diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index dfcc6c7367..fb0fed6d50 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -1794,15 +1794,6 @@ namespace Slang constraints.loc = context.loc; constraints.genericDecl = genericDeclRef.getDecl(); - List membersToResolve; - for (auto i : constraints.genericDecl->members) - { - if (as(i)) - continue; - membersToResolve.add(i); - } - auto innerDecl = genericDeclRef.getDecl()->inner; - // In order to perform matching between the types passed in at the // call site represented by `context` and the parameters of the // declaraiton being applied, we want to form a reference to @@ -1812,150 +1803,75 @@ namespace Slang // Check what type of declaration we are dealing with, and then try // to match it up with the arguments accordingly... - if (as(genericDeclRef.getDecl()->inner)) + if (auto funcDeclRef = as(genericDeclRef.getDecl()->inner)) { - // We have a ctor. We need to get the underlying callable. - // We have a ctor, we can assume that the generic arg list is equal to our return type - // arg list - auto functionVarExpr = as(context.originalExpr->functionExpr); - if (auto genericFunctionDeclRef = as(functionVarExpr->declRef)) + List paramTypes; + if (!innerParameterTypes) { - // Figure out what ctor we are using if our base is a struct decl - StructDecl* baseStruct = nullptr; - if (auto genericStructDecl = as(genericFunctionDeclRef.getDecl())) - baseStruct = as(genericStructDecl->inner); - if (baseStruct) + auto params = getParameters(m_astBuilder, funcDeclRef).toArray(); + for (auto param : params) { - // TODO: search for valid ctor "more correctly" - auto ctorList = _getCtorList(getASTBuilder(), this, baseStruct, nullptr); - for (auto& i : ctorList) - { - if (i->getParameters().getCount() != context.argCount) - continue; - innerDecl = i; - break; - } + paramTypes.add(getParamQualType(m_astBuilder, param)); } + innerParameterTypes = ¶mTypes; } - } - // TODO: Infer generics using return-type with parameter-list correctly through checking function body. + ShortList matchedArgs; - // Infer generic based on return-type with ctor - // TODO: mix with deducing generics from parameter list, if we do this we will be able - // to use this logic for all ctor's. This addition would be required since otherwise - // a return-type which is type "U" may be more ambiguous than a parameter of type "int" - // and cause compile error. - if (as(innerDecl) - && as(innerDecl)->containsOption(ConstructorTags::Synthesized) - && context.originalExpr && context.originalExpr->type.type) - { - if (auto declRefType = as(context.originalExpr->type.type)) + // We now try to match arguments to parameters. + // + // Note that if there are *too few* arguments, we might still have + // a match, because the other arguments might have default values + // that can be used. + // + if (!context.matchArgumentsToParams(this, *innerParameterTypes, true, matchedArgs)) { - if (auto genericAppDeclRef = as(declRefType->getDeclRefBase())) - { - Index genericDeclArgIndex = 0; - auto genericDeclArgCount = membersToResolve.getCount(); - - Index genericAppDeclRefIndex = 0; - auto genericAppDeclRefArgCount = genericAppDeclRef->getArgCount(); - - while (genericAppDeclRefArgCount > genericAppDeclRefIndex - && genericDeclArgCount > genericDeclArgIndex) - { - auto genericAppDeclRefArg = genericAppDeclRef->getArg(genericAppDeclRefIndex); - if (as(genericAppDeclRefArg)) - { - genericAppDeclRefIndex++; - continue; - } - - auto genericDeclArg = membersToResolve[genericDeclArgIndex]; - - Constraint constraint; - constraint.decl = genericDeclArg; - constraint.val = genericAppDeclRefArg; - constraints.constraints.add(constraint); - - genericDeclArgIndex++; - genericAppDeclRefIndex++; - } - } + return DeclRef(); } - } - if(constraints.constraints.getCount() == 0) - { - // Infer generics using parameters to function - if (auto funcDeclRef = as(innerDecl)) + // Perform type unification between arguments and parameters, so + // we can populate the resolve system with inital constraints. + // + for (Index aa = 0; aa < matchedArgs.getCount(); ++aa) { - List paramTypes; - if (!innerParameterTypes) - { - auto params = getParameters(m_astBuilder, funcDeclRef).toArray(); - for (auto param : params) - { - paramTypes.add(getParamQualType(m_astBuilder, param)); - } - innerParameterTypes = ¶mTypes; - } - - ShortList matchedArgs; - - // We now try to match arguments to parameters. + // The question here is whether failure to "unify" an argument + // and parameter should lead to immediate failure. // - // Note that if there are *too few* arguments, we might still have - // a match, because the other arguments might have default values - // that can be used. + // The case that is interesting is if we want to unify, say: + // `vector` and `vector` // - if (!context.matchArgumentsToParams(this, *innerParameterTypes, true, matchedArgs)) - { - return DeclRef(); - } - - // Perform type unification between arguments and parameters, so - // we can populate the resolve system with inital constraints. + // It is clear that we should solve with `N = 3`, and then + // a later step may find that the resulting types aren't + // actually a match. + // + // A more refined approach to "unification" could of course + // see that `int` can convert to `float` and use that fact. + // (and indeed we already use something like this to unify + // `float` and `vector`) // - for (Index aa = 0; aa < matchedArgs.getCount(); ++aa) + // So the question is then whether a mismatch during the + // unification step should be taken as an immediate failure... + auto argType = matchedArgs[aa].argType; + auto paramType = (*innerParameterTypes)[aa]; + auto canUnify = TryUnifyTypes( + constraints, + ValUnificationContext(), + QualType(argType, paramType.isLeftValue), + paramType); + + // It is an error if we can't unify the argument with a type pack parameter. + if (!canUnify && isTypePack(paramType)) { - // The question here is whether failure to "unify" an argument - // and parameter should lead to immediate failure. - // - // The case that is interesting is if we want to unify, say: - // `vector` and `vector` - // - // It is clear that we should solve with `N = 3`, and then - // a later step may find that the resulting types aren't - // actually a match. - // - // A more refined approach to "unification" could of course - // see that `int` can convert to `float` and use that fact. - // (and indeed we already use something like this to unify - // `float` and `vector`) - // - // So the question is then whether a mismatch during the - // unification step should be taken as an immediate failure... - auto argType = matchedArgs[aa].argType; - auto paramType = (*innerParameterTypes)[aa]; - auto canUnify = TryUnifyTypes( - constraints, - ValUnificationContext(), - QualType(argType, paramType.isLeftValue), - paramType); - - // It is an error if we can't unify the argument with a type pack parameter. - if (!canUnify && isTypePack(paramType)) - { - return DeclRef(); - } + return DeclRef(); } } - else - { - // TODO(tfoley): any other cases needed here? - return DeclRef(); - } } + else + { + // TODO(tfoley): any other cases needed here? + return DeclRef(); + } + // Once we have added all the appropriate constraints to the system, we // will try to solve for a set of arguments to the generic that satisfy // those constraints. @@ -1967,7 +1883,8 @@ namespace Slang // TODO(tfoley): We probably need to pass along the explicit arguments here, // so that the solver knows to accept those arguments as-is. // - return trySolveConstraintSystem(&constraints, genericDeclRef, knownGenericArgs, outBaseCost); + return trySolveConstraintSystem( + &constraints, genericDeclRef, knownGenericArgs, outBaseCost); } void SemanticsVisitor::AddTypeOverloadCandidates( @@ -2502,7 +2419,7 @@ namespace Slang // We allow a special case for when `funcExpr` is expected to be a Default initializer // but none exist. Note, we cannot just create a default initializer for every variable // since then we are introducing initialization to every variable through an indirect - // init returning data. + // init returning data. Instead we will call `$ZeroInit` through this logic below. if (context.argCount == 0) { auto oldMode = context.mode; diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index ab2b5045b0..64932330dc 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -179,7 +179,7 @@ namespace Slang { SLANG_ASSERT(structDecl); - // 1. Prefer non-synth default-ctor + // 1. Prefer non-synth default-ctor // * Skip this option if `ConstructZeroInitListOptions::PreferZeroInitFunc` is true // * Skip this option if `ConstructZeroInitListOptions::CheckToAvoidRecursion` detects recursion // * Only user-defined ctor will try and have recursion of `{}` diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index e31c5e31da..568547fd05 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -659,7 +659,7 @@ DIAGNOSTIC(38027, Error, mismatchExistentialSlotArgCount, "expected $0 existenti DIAGNOSTIC(38029, Error, typeArgumentDoesNotConformToInterface, "type argument '$0' does not conform to the required interface '$1'") DIAGNOSTIC(38031, Error, invalidUseOfNoDiff, "'no_diff' can only be used to decorate a call or a subscript operation") -DIAGNOSTIC(38032, Error, useOfNoDiffOnDifferentiableFunc, "use 'no_diff' on a call to a differentiable function has no meaning.") +DIAGNOSTIC(38032, Error, useOfNoDiffOnDifferentiableFunc, "using 'no_diff' on a call to a differentiable function has no meaning.") DIAGNOSTIC(38033, Error, cannotUseNoDiffInNonDifferentiableFunc, "cannot use 'no_diff' in a non-differentiable function.") DIAGNOSTIC(38034, Error, cannotUseConstRefOnDifferentiableParameter, "cannot use '__constref' on a differentiable parameter.") DIAGNOSTIC(38034, Error, cannotUseConstRefOnDifferentiableMemberMethod, "cannot use '[constref]' on a differentiable member method of a differentiable type.") diff --git a/tests/language-feature/initializer-lists/cstyle-init-list.slang b/tests/language-feature/initializer-lists/cstyle-init-list.slang index 51a41e38c5..228d7d4e05 100644 --- a/tests/language-feature/initializer-lists/cstyle-init-list.slang +++ b/tests/language-feature/initializer-lists/cstyle-init-list.slang @@ -20,10 +20,10 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) && test[0].a == 1 && test[0].b == 2 - && test[1].a == 1 - && test[1].b == 2 + && test[1].a == 3 + && test[1].b == 4 - && test[2].a == 1 - && test[2].b == 2 + && test[2].a == 5 + && test[2].b == 6 ; } \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes.slang b/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes.slang new file mode 100644 index 0000000000..a747686988 --- /dev/null +++ b/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes.slang @@ -0,0 +1,41 @@ +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute + +struct TestInner : IDifferentiable +{ + typealias Differential = TestInner; + int a; +} +struct Test : IDifferentiable +{ + uint a; + uint b; + TestInner test; + + [Differentiable] + __init(uint data1, uint data2, TestInner data) + { + a = data1; + b = data2; + test = {}; + } +}; + +struct Test2 : IDifferentiable +{ + typealias Differential = Test2; + TestInner a; +} + +//CHECK: computeMain + +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test.Differential test = { {} }; + + outputBuffer[0] = true + && test.test.a == 0 + ; +} \ No newline at end of file From 06eea8268b29dd312602d850e5de03e0f62d1062 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:01:01 -0400 Subject: [PATCH 055/100] 1. Fix isCStyleCtor evaluation 2. update autodiff.slang test to modern style --- source/slang/slang-check-decl.cpp | 77 +++++++++++----------- source/slang/slang-constructor-utility.cpp | 17 ----- tests/diagnostics/autodiff.slang | 11 +++- tests/diagnostics/autodiff.slang.expected | 14 ---- 4 files changed, 49 insertions(+), 70 deletions(-) delete mode 100644 tests/diagnostics/autodiff.slang.expected diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 9fc48f3e7f..619f707545 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1829,16 +1829,6 @@ namespace Slang { VarDeclBase* m_argToCopy; Expr* m_initExpr = nullptr; - - // Do not add initExpr to list since other-wise we will have more than 1 'default ctor' - // which Slang disallows. - static void addArgToList(List& argList, VarDeclBase* argToCopy, Expr* initExpr) - { - if(argList.getCount() == 0) - argList.add({ argToCopy, nullptr }); - else - argList.add({ argToCopy, initExpr }); - } }; static ConstructorDecl* _createCtor( SemanticsDeclVisitorBase* visitor, @@ -10588,8 +10578,6 @@ namespace Slang structDecl->addMember(zeroInitFunc); } - bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); - // Add an empty constructor for all combinations of visibility and access // which is possible: // 1. public constructor - usable *outside class scope* in a *different module* @@ -10597,7 +10585,7 @@ namespace Slang // 2. public-internal constructor - usable *outside class scope* in the *same module* List publicInternalCtorArgs; // 3. public-private-internal constructor - usable *inside class scope* in the *same module* - List publicPrivateInternalCtorArgs; + List publicInternalPrivateCtorArgs; // Harvest parameters which map to the base type ctor. // Note: assumes 1 structDecl, N number inheritance decl @@ -10637,20 +10625,12 @@ namespace Slang { for (auto i : ctorForPublic->getParameters()) { - Expr* initExpr = nullptr; - if (isCStyleStruct) - initExpr = createDefaultConstructExprForType(m_astBuilder, QualType(i->type), {}); - - CreateCtorArg::addArgToList(publicCtorArgs, i, initExpr); + publicCtorArgs.add({ i,nullptr }); } for (auto i : ctorForInternal->getParameters()) { - Expr* initExpr = nullptr; - if (isCStyleStruct) - initExpr = createDefaultConstructExprForType(m_astBuilder, QualType(i->type), {}); - - CreateCtorArg::addArgToList(publicInternalCtorArgs, i, initExpr); - CreateCtorArg::addArgToList(publicPrivateInternalCtorArgs, i, initExpr); + publicInternalCtorArgs.add({ i,nullptr }); + publicInternalPrivateCtorArgs.add({ i,nullptr }); } } } @@ -10668,29 +10648,25 @@ namespace Slang // Do not map a read-only variable for default-init if (!getTypeForDeclRef(m_astBuilder, varDeclRef, varDeclRef.getLoc()).isLeftValue) continue; - - Expr* initExpr = nullptr; - if (isCStyleStruct) - initExpr = createDefaultConstructExprForType(m_astBuilder, QualType(varDecl->type), {}); - + auto declVisibility = getDeclVisibility(varDecl); switch (declVisibility) { case DeclVisibility::Private: - CreateCtorArg::addArgToList(publicPrivateInternalCtorArgs, varDecl, initExpr); + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); if(!varDecl->initExpr) maxVisibilityCtorToGenerate = DeclVisibility::Private; break; case DeclVisibility::Internal: - CreateCtorArg::addArgToList(publicPrivateInternalCtorArgs, varDecl, initExpr); - CreateCtorArg::addArgToList(publicInternalCtorArgs, varDecl, initExpr); + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + publicInternalCtorArgs.add({ varDecl, nullptr }); if (!varDecl->initExpr) maxVisibilityCtorToGenerate = DeclVisibility::Internal; break; case DeclVisibility::Public: - CreateCtorArg::addArgToList(publicPrivateInternalCtorArgs, varDecl, initExpr); - CreateCtorArg::addArgToList(publicInternalCtorArgs, varDecl, initExpr); - CreateCtorArg::addArgToList(publicCtorArgs, varDecl, initExpr); + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + publicInternalCtorArgs.add({ varDecl, nullptr }); + publicCtorArgs.add({ varDecl, nullptr }); break; default: // Unknown visibility @@ -10699,12 +10675,37 @@ namespace Slang } } + List generatedMemberwiseCtors; if (maxVisibilityCtorToGenerate >= DeclVisibility::Public) - _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public); + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public)) + generatedMemberwiseCtors.add(generatedCtor); if (maxVisibilityCtorToGenerate >= DeclVisibility::Internal) - _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal); + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal)) + generatedMemberwiseCtors.add(generatedCtor); if (maxVisibilityCtorToGenerate >= DeclVisibility::Private) - _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicPrivateInternalCtorArgs), ctorList, structDecl, DeclVisibility::Private); + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalPrivateCtorArgs), ctorList, structDecl, DeclVisibility::Private)) + generatedMemberwiseCtors.add(generatedCtor); + + // `checkIfCStyleStruct` must check after we add all possible Ctors. + // If we are a CStyleStruct add DefaultConstructExpr to all params (excluding arg 0) + bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); + if (isCStyleStruct && generatedMemberwiseCtors.getCount() > 0) + { + // We know the user provided 0 non-default ctor's, we only had a chance to generate non default Ctors above in this AST pass. + SLANG_ASSERT(generatedMemberwiseCtors.getCount() == 1); + for (auto generatedCtor : generatedMemberwiseCtors) + { + Index paramIndex = 0; + for (ParamDecl* i : generatedCtor->getParameters()) + { + // Never annotate the first parameter to prevent conflict with "DefaultCtor" + if (paramIndex == 0) + continue; + + i->initExpr = createDefaultConstructExprForType(this->getASTBuilder(), (QualType)i->type, i->loc); + } + } + } int backingWidth = 0; [[maybe_unused]] diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index 64932330dc..60e820bbae 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -275,23 +275,6 @@ namespace Slang return false; } } - - // We need this additional check if we did not resolve all ctor's based on visibility yet - if (!structDecl->isChecked(DeclCheckState::AttributesChecked)) - { - HashSet visibilities; - for (auto i : getMembersOfType(visitor->getASTBuilder(), structDecl, MemberFilterStyle::Instance)) - { - visibilities.add(getDeclVisibility(i.getDecl())); - if (visibilities.getCount() != 1) - { - visitor->getShared()->cacheIsCStyleStruct(structDecl, false); - return false; - } - } - } - - visitor->getShared()->cacheIsCStyleStruct(structDecl, true); return true; } } diff --git a/tests/diagnostics/autodiff.slang b/tests/diagnostics/autodiff.slang index 7905b48b6d..36ac69c7cf 100644 --- a/tests/diagnostics/autodiff.slang +++ b/tests/diagnostics/autodiff.slang @@ -1,4 +1,13 @@ -//DIAGNOSTIC_TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): + +//CHECK: tests/diagnostics/autodiff.slang({{..}}): error 38031: +//CHECK-NEXT: float x1 = no_diff x; + +//CHECK: tests/diagnostics/autodiff.slang({{..}}): error 38032: +//CHECK-NEXT: return no_diff f(x); + +//CHECK: tests/diagnostics/autodiff.slang({{..}}): error 38033: +//CHECK-NEXT: return no_diff nonDiff(x); float nonDiff(float x) { diff --git a/tests/diagnostics/autodiff.slang.expected b/tests/diagnostics/autodiff.slang.expected deleted file mode 100644 index 95da2a6d3b..0000000000 --- a/tests/diagnostics/autodiff.slang.expected +++ /dev/null @@ -1,14 +0,0 @@ -result code = -1 -standard error = { -tests/diagnostics/autodiff.slang(30): error 38031: 'no_diff' can only be used to decorate a call or a subscript operation - float x1 = no_diff x; // invalid use of no_diff here. - ^~~~~~~ -tests/diagnostics/autodiff.slang(31): error 38032: use 'no_diff' on a call to a differentiable function has no meaning. - return no_diff f(x); // no_diff on a differentiable call has no meaning. - ^~~~~~~ -tests/diagnostics/autodiff.slang(36): error 38033: cannot use 'no_diff' in a non-differentiable function. - return no_diff nonDiff(x); // no_diff in a non-differentiable function - ^~~~~~~ -} -standard output = { -} From bac6c317695342e22f771d0ec15e47ad75c7f224 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:57:25 -0400 Subject: [PATCH 056/100] fix partial init list bug --- source/slang/slang-check-decl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 619f707545..0b26472f12 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -10702,6 +10702,7 @@ namespace Slang if (paramIndex == 0) continue; + paramIndex++; i->initExpr = createDefaultConstructExprForType(this->getASTBuilder(), (QualType)i->type, i->loc); } } From fb8588e5ab08dc1856d255d50fb19b7e052866db Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 30 Aug 2024 17:19:43 -0400 Subject: [PATCH 057/100] fix the bug correctly* --- source/slang/slang-check-decl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 0b26472f12..0d9e04d3ea 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -10700,8 +10700,10 @@ namespace Slang { // Never annotate the first parameter to prevent conflict with "DefaultCtor" if (paramIndex == 0) + { + paramIndex++; continue; - + } paramIndex++; i->initExpr = createDefaultConstructExprForType(this->getASTBuilder(), (QualType)i->type, i->loc); } From 39bd24de326800f8ab96a2f8026a70c02b2bcbf2 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Mon, 2 Sep 2024 23:24:06 -0400 Subject: [PATCH 058/100] fix some simple problems 1. problem with dxil causing infinite loop (slang-ir.cpp, slang-ir-specialize-resources.cpp) 2. hlsl.meta so it doesn't use a limitation of generics that cause a crash (hlsl.meta.slang) --- source/slang/hlsl.meta.slang | 12 +++++--- .../slang/slang-ir-specialize-resources.cpp | 10 +++++-- source/slang/slang-ir.cpp | 2 +- ...nit-list-with-autodiff-attributes-1.slang} | 0 ...init-list-with-autodiff-attributes-2.slang | 30 +++++++++++++++++++ 5 files changed, 47 insertions(+), 7 deletions(-) rename tests/language-feature/initializer-lists/{init-list-with-autodiff-attributes.slang => init-list-with-autodiff-attributes-1.slang} (100%) create mode 100644 tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-2.slang diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 3601354863..d072ab834b 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -19962,8 +19962,9 @@ ${ case hlsl: uint isSingleLod = 0; + int shapeDim = Shape.dimensions; Footprint footprint = {__queryFootprint$(CoarseOrFine)NVAPI( - Shape.dimensions, + shapeDim, __getRegisterSpace(this), __getRegisterIndex(this), __getRegisterSpace(sampler), __getRegisterIndex(sampler), __vectorReshape<3>(coords), granularity, /* out */isSingleLod), false}; @@ -19995,8 +19996,9 @@ ${ return footprint; case hlsl: uint isSingleLod = 0; + int shapeDim = Shape.dimensions; Footprint footprint = {__queryFootprint$(CoarseOrFine)BiasNVAPI( - Shape.dimensions, + shapeDim, __getRegisterSpace(this), __getRegisterIndex(this), __getRegisterSpace(sampler), __getRegisterIndex(sampler), __vectorReshape<3>(coords), granularity, lodBias, /* out */isSingleLod), false}; @@ -20078,8 +20080,9 @@ ${ return footprint; case hlsl: uint isSingleLod = 0; + int shapeDim = Shape.dimensions; Footprint footprint = {__queryFootprint$(CoarseOrFine)LevelNVAPI( - Shape.dimensions, + shapeDim, __getRegisterSpace(this), __getRegisterIndex(this), __getRegisterSpace(sampler), __getRegisterIndex(sampler), __vectorReshape<3>(coords), granularity, lod, /* out */isSingleLod), false}; @@ -20117,8 +20120,9 @@ ${{{ return footprint; case hlsl: uint isSingleLod = 0; + int shapeDim = Shape.dimensions; Footprint footprint = {__queryFootprint$(CoarseOrFine)GradNVAPI( - Shape.dimensions, + shapeDim, __getRegisterSpace(this), __getRegisterIndex(this), __getRegisterSpace(sampler), __getRegisterIndex(sampler), __vectorReshape<3>(coords), granularity, __vectorReshape<3>(dx), __vectorReshape<3>(dy), /* out */isSingleLod), false}; diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp index 5e15098d42..23b227399a 100644 --- a/source/slang/slang-ir-specialize-resources.cpp +++ b/source/slang/slang-ir-specialize-resources.cpp @@ -248,7 +248,10 @@ struct ResourceOutputSpecializationPass newFunc->removeAndDeallocate(); // Check if `oldFunc` is the reason for failing, // Otherwise don't add to 'unspecializableFuncs' - if(result == SpecializeFuncResult::ThisFuncFailed) + // + // Also ensure our func has uses, else we can just ignore specializing this function. + // Otherwise 'KeepAlive' will cause an infinite loop. + if(result == SpecializeFuncResult::ThisFuncFailed && oldFunc->hasUses()) unspecializableFuncs->add(oldFunc); return false; } @@ -309,12 +312,15 @@ struct ResourceOutputSpecializationPass // There should be no conditions at call sites that can cause specialization to // fail, because specialization does not depend on what is passed *in* to each // call, but only on what gets passed *out*. - // for( auto oldCall : calls ) { specializeCallSite(oldCall, newFunc, funcInfo); } specializedFuncs.add(oldFunc); + + // Since we can no longer fail and we are replacing all `Func` uses, all 'KeepAlive's + // can be removed from the oldFunc so DCE can it clean-up. + oldFunc->findDecoration()->removeAndDeallocate(); return true; } diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 228412e6e9..3ed317d1db 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -3738,7 +3738,7 @@ namespace Slang IRInst* IRBuilder::_emitDefaultConstruct(IRType* type, bool fallback, HashSet visitedTypes) { - if (visitedTypes.contains(type)) + if (visitedTypes.contains(type) || isResourceType(type)) return emitUndefined(type); visitedTypes.add(type); IRType* actualType = type; diff --git a/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes.slang b/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-1.slang similarity index 100% rename from tests/language-feature/initializer-lists/init-list-with-autodiff-attributes.slang rename to tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-1.slang diff --git a/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-2.slang b/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-2.slang new file mode 100644 index 0000000000..aa35c4d412 --- /dev/null +++ b/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-2.slang @@ -0,0 +1,30 @@ +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute + +struct Test : IDifferentiable +{ + float3 a; + no_diff float3 b; +}; + +//CHECK: computeMain + +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test.Differential test1 = {}; + Test test2 = {}; + outputBuffer[0] = true + && test1.a[0] == 0 + && test1.a[1] == 0 + && test1.a[2] == 0 + + && test1.a[0] == 0 + && test1.a[1] == 0 + && test1.a[2] == 0 + && test1.b[0] == 0 + && test1.b[1] == 0 + && test1.b[2] == 0 + ; +} \ No newline at end of file From e9a903503374923f23f8471c4293493e6a958e11 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 3 Sep 2024 00:22:30 -0400 Subject: [PATCH 059/100] ignore undefined resource var's --- source/slang/slang-ir-use-uninitialized-values.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/slang/slang-ir-use-uninitialized-values.cpp b/source/slang/slang-ir-use-uninitialized-values.cpp index b48dadf8db..202d44e9d4 100644 --- a/source/slang/slang-ir-use-uninitialized-values.cpp +++ b/source/slang/slang-ir-use-uninitialized-values.cpp @@ -154,6 +154,10 @@ namespace Slang if (!type) return true; + // In case we have a resource type (which can be assigned values in many unpredictable ways) + if (isResourceType(type)) + return true; + if (as(type)) return true; From f6b1b4afa6cbce2f596c38888a757244737430fc Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 3 Sep 2024 09:56:17 -0400 Subject: [PATCH 060/100] check IRNode exists before deallocating --- source/slang/slang-ir-specialize-resources.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp index 23b227399a..da709b8b49 100644 --- a/source/slang/slang-ir-specialize-resources.cpp +++ b/source/slang/slang-ir-specialize-resources.cpp @@ -318,9 +318,10 @@ struct ResourceOutputSpecializationPass } specializedFuncs.add(oldFunc); - // Since we can no longer fail and we are replacing all `Func` uses, all 'KeepAlive's - // can be removed from the oldFunc so DCE can it clean-up. - oldFunc->findDecoration()->removeAndDeallocate(); + // Since we can no longer fail and we are replacing all `Func` uses of 'KeepAlive'. + // This is done so DCE can clean-up our unspecialized version of our function. + if(auto keepAliveDecoration = oldFunc->findDecoration()) + keepAliveDecoration->removeAndDeallocate(); return true; } From b7654d409093742877808752287d5276ddeb4409 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 3 Sep 2024 11:03:32 -0400 Subject: [PATCH 061/100] fix possible cyclic ref & change `_emitDefaultConstruct` so it cannot emit invalid struct-value --- source/slang/slang-ast-support-types.h | 1 + source/slang/slang-check-conversion.cpp | 11 +++- source/slang/slang-check-decl.cpp | 74 ++++++++++++++----------- source/slang/slang-ir.cpp | 2 + 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index 21948dc040..4c87c0bd2a 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -491,6 +491,7 @@ namespace Slang CanUseFuncSignature = ReadyForReference, CanSpecializeGeneric = ReadyForReference, CanReadInterfaceRequirements = ReadyForLookup, + CanUseZeroInit = SignatureChecked, }; /// A `DeclCheckState` plus a bit to track whether a declaration is currently being checked. diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index b492d1a502..b6c56614e3 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -450,10 +450,12 @@ namespace Slang if(auto toStructDeclRef = toTypeDeclRef.as()) { auto toStructDecl = toStructDeclRef.getDecl(); - ensureDecl(toStructDecl, DeclCheckState::DefaultConstructorReadyForUse); - List ctorList = _getCtorList(this->getASTBuilder(), this, toStructDecl, nullptr); - bool allowCStyleInitList = checkIfCStyleStruct(this, toStructDecl); + // Note: Since $ZeroInit gets generated at `DeclCheckState::CanUseFuncSignature` + // we can safely assume that if this logic runs before constructors are + // synthisized in `SemanticsAttributesVisitor`, this is fallback default-ctor + // logic. + ensureDecl(toStructDecl, DeclCheckState::CanUseZeroInit); // Easy case of default constructor or equivalent if (argCount == 0) @@ -466,6 +468,9 @@ namespace Slang return true; } + List ctorList = _getCtorList(this->getASTBuilder(), this, toStructDecl, nullptr); + bool allowCStyleInitList = checkIfCStyleStruct(this, toStructDecl); + // Non-default constructor case List maybeArgList; maybeArgList.reserve(argCount); diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 00f4460e52..9092aa0c78 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1921,6 +1921,43 @@ namespace Slang structDecl->addMember(member); } checkVisibility(structDecl); + + // Generate $ZeroInit. Since this is a place-holder non-ctor, we can pre-generate this function early. + // Note: some modfiers cannot be added at this stage, these will be added later in our AST passes. + if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getCount() != 0) + { + // $ZeroInit is a synthisized static-function only used In 2 cases: + // 1. if `{}` is used inside a `__init()` + // 2. if `{}` is used and a user has a 'synthisized __init()` + // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. + auto zeroInitFunc = m_astBuilder->create(); + auto ctorName = getName("$ZeroInit"); + zeroInitFunc->ownedScope = m_astBuilder->create(); + zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; + zeroInitFunc->ownedScope->parent = getScope(structDecl); + zeroInitFunc->parentDecl = structDecl; + zeroInitFunc->loc = structDecl->loc; + zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; + zeroInitFunc->nameAndLoc.name = ctorName; + zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; + zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); + auto body = m_astBuilder->create(); + body->scopeDecl = m_astBuilder->create(); + body->scopeDecl->ownedScope = m_astBuilder->create(); + body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); + body->scopeDecl->parentDecl = zeroInitFunc; + body->scopeDecl->loc = zeroInitFunc->loc; + body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; + body->closingSourceLoc = zeroInitFunc->closingSourceLoc; + zeroInitFunc->body = body; + body->body = m_astBuilder->create(); + + addModifier(zeroInitFunc, m_astBuilder->create()); + addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); + addModifier(zeroInitFunc, m_astBuilder->create()); + structDecl->addMember(zeroInitFunc); + } + } void SemanticsDeclHeaderVisitor::visitClassDecl(ClassDecl* classDecl) @@ -10575,40 +10612,13 @@ namespace Slang ctorList.add(defaultCtor); } - if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getCount() != 0) + // Add auto-diff modifiers to $ZeroInit + if (auto zeroInitFunc = findZeroInitListFunc(structDecl)) { - // $ZeroInit is a synthisized static-function only used In 2 cases: - // 1. if `{}` is used inside a `__init()` - // 2. if `{}` is used and a user has a 'synthisized __init()` - // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. - auto zeroInitFunc = m_astBuilder->create(); - auto ctorName = getName("$ZeroInit"); - zeroInitFunc->ownedScope = m_astBuilder->create(); - zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; - zeroInitFunc->ownedScope->parent = getScope(structDecl); - zeroInitFunc->parentDecl = structDecl; - zeroInitFunc->loc = structDecl->loc; - zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; - zeroInitFunc->nameAndLoc.name = ctorName; - zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; - zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); - auto body = m_astBuilder->create(); - body->scopeDecl = m_astBuilder->create(); - body->scopeDecl->ownedScope = m_astBuilder->create(); - body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); - body->scopeDecl->parentDecl = zeroInitFunc; - body->scopeDecl->loc = zeroInitFunc->loc; - body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; - body->closingSourceLoc = zeroInitFunc->closingSourceLoc; - zeroInitFunc->body = body; - body->body = m_astBuilder->create(); - - addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); + // Since we are zero-initializing, we are effectively `TreatAsDifferentiableAttribute`. + // This is important since some prior use-cases have no_diff on our `$ZeroInit` use-cases. + addModifier(zeroInitFunc, m_astBuilder->create()); addModifier(zeroInitFunc, m_astBuilder->create()); - addModifier(zeroInitFunc, m_astBuilder->create()); - addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); - addModifier(zeroInitFunc, m_astBuilder->create()); - structDecl->addMember(zeroInitFunc); } // Add an empty constructor for all combinations of visibility and access diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 3ed317d1db..aa91c3770c 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -3820,6 +3820,8 @@ namespace Slang return nullptr; elements.add(inner); } + if(elements.getCount() == 0) + return emitUndefined(type); return emitMakeStruct(type, elements); } case kIROp_ArrayType: From d5c7e16e978abb2ae6fe37c96bfd9c54cd610b93 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:45:46 -0400 Subject: [PATCH 062/100] fix order of evaluation to prevent crash (not auto-diff fixes) --- source/slang/slang-ast-support-types.h | 2 +- source/slang/slang-check-conversion.cpp | 6 +----- source/slang/slang-check-decl.cpp | 24 ++++++++++++++---------- source/slang/slang-ir.cpp | 2 -- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index 4c87c0bd2a..dc97a923d1 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -470,7 +470,6 @@ namespace Slang /// functions, so it belongs in the last phase of checking. /// DefinitionChecked, - DefaultConstructorReadyForUse = DefinitionChecked, /// The capabilities required by the decl is infered and validated. /// @@ -492,6 +491,7 @@ namespace Slang CanSpecializeGeneric = ReadyForReference, CanReadInterfaceRequirements = ReadyForLookup, CanUseZeroInit = SignatureChecked, + DefaultConstructorReadyForUse = AttributesChecked, }; /// A `DeclCheckState` plus a bit to track whether a declaration is currently being checked. diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index b6c56614e3..7483513903 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -451,11 +451,7 @@ namespace Slang { auto toStructDecl = toStructDeclRef.getDecl(); - // Note: Since $ZeroInit gets generated at `DeclCheckState::CanUseFuncSignature` - // we can safely assume that if this logic runs before constructors are - // synthisized in `SemanticsAttributesVisitor`, this is fallback default-ctor - // logic. - ensureDecl(toStructDecl, DeclCheckState::CanUseZeroInit); + ensureDecl(toStructDecl, DeclCheckState::DefaultConstructorReadyForUse); // Easy case of default constructor or equivalent if (argCount == 0) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 9092aa0c78..5b4088b666 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1924,7 +1924,7 @@ namespace Slang // Generate $ZeroInit. Since this is a place-holder non-ctor, we can pre-generate this function early. // Note: some modfiers cannot be added at this stage, these will be added later in our AST passes. - if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getCount() != 0) + if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getFirstOrNull()) { // $ZeroInit is a synthisized static-function only used In 2 cases: // 1. if `{}` is used inside a `__init()` @@ -8257,20 +8257,24 @@ namespace Slang { if (auto baseStructDecl = as(baseStructInfo->m_inheritanceBaseDecl)) { - Expr* zeroInitFunc = constructZeroInitListFunc(this, baseStructDecl, baseStructInfo->m_inheritanceDecl->base.type, ConstructZeroInitListOptions::PreferZeroInitFunc); - auto assign = m_astBuilder->create(); - assign->left = coerce(CoercionSite::Initializer, zeroInitFunc->type, structVarDeclExpr); - assign->right = zeroInitFunc; - auto stmt = m_astBuilder->create(); - stmt->expression = assign; - stmt->loc = seqStmt->loc; - seqStmt->stmts.add(stmt); + if (getMembersOfType(m_astBuilder, baseStructDecl, MemberFilterStyle::Instance).getFirstOrNull()) + { + Expr* zeroInitFunc = constructZeroInitListFunc(this, baseStructDecl, baseStructInfo->m_inheritanceDecl->base.type, ConstructZeroInitListOptions::PreferZeroInitFunc); + auto assign = m_astBuilder->create(); + assign->left = coerce(CoercionSite::Initializer, zeroInitFunc->type, structVarDeclExpr); + assign->right = zeroInitFunc; + auto stmt = m_astBuilder->create(); + stmt->expression = assign; + stmt->loc = seqStmt->loc; + seqStmt->stmts.add(stmt); + } } } // Assign initExpr to all members for (auto memberRef : membersOfStructDeclInstance) { + auto member = memberRef.getDecl(); addCudaHostModifierIfRequired(zeroInitListFunc, member, foundCudaHostModifier); @@ -10617,7 +10621,7 @@ namespace Slang { // Since we are zero-initializing, we are effectively `TreatAsDifferentiableAttribute`. // This is important since some prior use-cases have no_diff on our `$ZeroInit` use-cases. - addModifier(zeroInitFunc, m_astBuilder->create()); + addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); addModifier(zeroInitFunc, m_astBuilder->create()); } diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index aa91c3770c..3ed317d1db 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -3820,8 +3820,6 @@ namespace Slang return nullptr; elements.add(inner); } - if(elements.getCount() == 0) - return emitUndefined(type); return emitMakeStruct(type, elements); } case kIROp_ArrayType: From 6ea9950177ff93332e23e2fb59e2c70ff2314ea2 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:38:02 -0400 Subject: [PATCH 063/100] fix var check order --- source/slang/slang-ast-support-types.h | 1 + source/slang/slang-check-decl.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index dc97a923d1..d396f39c38 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -492,6 +492,7 @@ namespace Slang CanReadInterfaceRequirements = ReadyForLookup, CanUseZeroInit = SignatureChecked, DefaultConstructorReadyForUse = AttributesChecked, + VarInitExprAreChecked = DefinitionChecked, }; /// A `DeclCheckState` plus a bit to track whether a declaration is currently being checked. diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 5b4088b666..58657f1a4e 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7899,7 +7899,7 @@ namespace Slang auto varDeclBase = as(m); if (!varDeclBase) continue; - ensureDecl(m->getDefaultDeclRef(), DeclCheckState::DefaultConstructorReadyForUse); + ensureDecl(m->getDefaultDeclRef(), DeclCheckState::VarInitExprAreChecked); if (!isDefaultInitializableType || varDeclBase->initExpr) continue; @@ -8028,7 +8028,7 @@ namespace Slang DeclAndCtorInfo* baseStructInfo = nullptr; for(auto& i : inheritanceInfoList) { - ensureDecl(i.m_inheritanceDecl, DeclCheckState::DefinitionChecked); + ensureDecl(i.m_inheritanceDecl, DeclCheckState::VarInitExprAreChecked); if(as(i.m_inheritanceBaseDecl)) baseStructInfo = &i; } @@ -8234,7 +8234,7 @@ namespace Slang structVarDecl->initExpr = defaultConstructExpr; structVarDecl->parentDecl = zeroInitListFunc; structVarDecl->loc = seqStmt->loc; - ensureDecl(structVarDecl, DeclCheckState::DefaultConstructorReadyForUse); + ensureDecl(structVarDecl, DeclCheckState::VarInitExprAreChecked); auto structVarDeclExpr = m_astBuilder->create(); structVarDeclExpr->declRef = structVarDecl->getDefaultDeclRef(); From 5712dbb5e31041f68beb43b56ccbce8d4f63bf26 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:47:39 -0400 Subject: [PATCH 064/100] remove resource-spec change that is wrong --- source/slang/slang-ir-specialize-resources.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp index da709b8b49..5dd63ac6cc 100644 --- a/source/slang/slang-ir-specialize-resources.cpp +++ b/source/slang/slang-ir-specialize-resources.cpp @@ -248,10 +248,7 @@ struct ResourceOutputSpecializationPass newFunc->removeAndDeallocate(); // Check if `oldFunc` is the reason for failing, // Otherwise don't add to 'unspecializableFuncs' - // - // Also ensure our func has uses, else we can just ignore specializing this function. - // Otherwise 'KeepAlive' will cause an infinite loop. - if(result == SpecializeFuncResult::ThisFuncFailed && oldFunc->hasUses()) + if(result == SpecializeFuncResult::ThisFuncFailed) unspecializableFuncs->add(oldFunc); return false; } From 4956257813ca29e71836f18a20505c66fc2f4d5e Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Tue, 3 Sep 2024 19:43:31 -0400 Subject: [PATCH 065/100] remove failing test as per reccomendation (#4874) --- tests/compute/type-legalize-global-with-init.slang | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/compute/type-legalize-global-with-init.slang b/tests/compute/type-legalize-global-with-init.slang index 573ac98499..a3a1429aae 100644 --- a/tests/compute/type-legalize-global-with-init.slang +++ b/tests/compute/type-legalize-global-with-init.slang @@ -14,19 +14,15 @@ RWStructuredBuffer inputBuffer; static const RWStructuredBuffer gBuffer = inputBuffer; -struct Stuff -{ - RWStructuredBuffer a; - RWStructuredBuffer b; -} - -static const Stuff gStuff = { inputBuffer, inputBuffer }; +// Note: due to #4874 we cannot assign functions to globals +// which contain resource types. +static const RWStructuredBuffer gStuff = inputBuffer; uint test(uint x) { return gBuffer[x] - + gStuff.a[x + 1] * 16 - + gStuff.b[x + 2] * 256; + + gStuff[x + 1] * 16 + + gStuff[x + 2] * 256; } [numthreads(4, 1, 1)] From bb3fa44ff0168e379b30a192690610eca728ccd3 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 4 Sep 2024 10:01:27 -0400 Subject: [PATCH 066/100] remove specialize fix, fix recursive init calls --- source/slang/slang-check-decl.cpp | 435 +++++++++--------- .../slang/slang-ir-specialize-resources.cpp | 5 - .../extensions/this-in-extension.slang | 21 +- 3 files changed, 234 insertions(+), 227 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 58657f1a4e..035f12519a 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2533,6 +2533,73 @@ namespace Slang } } + + // Annotate ctor as a memberwise ctor. A non synthisized function may be annotated as a memberwise ctor + // if it has a compatible parameter list with a memberwise ctor. + void _annotateMemberwiseCtorWithVisibility(ConstructorDecl* ctor, DeclVisibility visibility) + { + switch (visibility) + { + case DeclVisibility::Public: + ctor->addOption(ConstructorTags::MemberwiseCtorForPublicVisibility); + break; + case DeclVisibility::Internal: + ctor->addOption(ConstructorTags::MemberwiseCtorForInternalVisibility); + break; + default: + break; + } + } + + static ConstructorDecl* _tryToGenerateCtorWithArgList( + SemanticsDeclVisitorBase* visitor, + ASTBuilder* astBuilder, + List&& args, + List& existingCtorList, + StructDecl* structDecl, + DeclVisibility visibility) + { + // Find any existing ctor type conflicts + for (auto ctor : existingCtorList) + { + auto existingCtorArgs = ctor->getParameters(); + auto existingCtorArgsLength = ctor->getParameters().getCount(); + auto newCtorArgsLength = args.getCount(); + + // Different arg count, ctor are not conflicting + if (existingCtorArgsLength != newCtorArgsLength) + continue; + + // if both arg lists are empty, return, we cannot have 2 default ctor's + if (!existingCtorArgsLength && !newCtorArgsLength) + return nullptr; + + // Check if every newCtorArg[i] is castable to existingCtorArg[i] (if so this is a conflicting ctor) + bool equalCtor = true; + for (Index i = 0; i < newCtorArgsLength; i++) + { + auto newCtorArg = args[i].m_argToCopy; + auto existingCtorArg = existingCtorArgs[i]; + if (visitor->getConversionCost(newCtorArg->getType(), existingCtorArg->getType()) == kConversionCost_Impossible) + { + equalCtor = false; + break; + } + } + if (equalCtor) + { + _annotateMemberwiseCtorWithVisibility(ctor, visibility); + return nullptr; + } + } + + // We did not have any ctor conflicts, auto-generate a ctor + auto generatedCtor = _createCtor(visitor, astBuilder, structDecl, std::move(args), visibility); + existingCtorList.add(generatedCtor); + _annotateMemberwiseCtorWithVisibility(generatedCtor, visibility); + return generatedCtor; + } + // Concretize interface conformances so that we have witnesses as required for lookup. // for lookup. struct SemanticsDeclConformancesVisitor @@ -2551,6 +2618,158 @@ namespace Slang // void visitAggTypeDecl(AggTypeDecl* aggTypeDecl) { + if (auto structDecl = as(aggTypeDecl)) + { + // Add an empty default-ctor if missing a real default-ctor. + ConstructorDecl* defaultCtor = nullptr; + List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); + if (!defaultCtor) + { + defaultCtor = _createCtor(this, m_astBuilder, structDecl, {}, getDeclVisibility(structDecl)); + ctorList.add(defaultCtor); + } + + // Add auto-diff modifiers to $ZeroInit + if (auto zeroInitFunc = findZeroInitListFunc(structDecl)) + { + // Since we are zero-initializing, we are effectively `TreatAsDifferentiableAttribute`. + // This is important since some prior use-cases have no_diff on our `$ZeroInit` use-cases. + addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); + addModifier(zeroInitFunc, m_astBuilder->create()); + } + + // Add an empty constructor for all combinations of visibility and access + // which is possible: + // 1. public constructor - usable *outside class scope* in a *different module* + List publicCtorArgs; + // 2. public-internal constructor - usable *outside class scope* in the *same module* + List publicInternalCtorArgs; + // 3. public-private-internal constructor - usable *inside class scope* in the *same module* + List publicInternalPrivateCtorArgs; + + // Harvest parameters which map to the base type ctor. + // Note: assumes 1 structDecl, N number inheritance decl + for (auto inheritanceMember : structDecl->getMembersOfType()) + { + auto declRefType = as(inheritanceMember->base.type); + if (!declRefType) + continue; + auto baseStruct = as(declRefType->getDeclRef().getDecl()); + if (!baseStruct) + continue; + + DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; + + ConstructorDecl* ctorForPublic = nullptr; + ConstructorDecl* ctorForInternal = nullptr; + + // From our synthisized ctor's find the publicMemberCtor and internalMemberCtor. + List baseCtorList = _getCtorList(this->getASTBuilder(), this, baseStruct, nullptr); + for (auto i : baseCtorList) + { + if (i->containsOption(ConstructorTags::MemberwiseCtorForPublicVisibility)) + ctorForPublic = i; + if (i->containsOption(ConstructorTags::MemberwiseCtorForInternalVisibility)) + ctorForInternal = i; + } + + // If base is not defined in the same module (or if the internal ctor is missing) + // set the parameter list to a base-type member-wise ctor. + if (baseVisibilityToDerived == DeclVisibility::Public + || !ctorForInternal) + { + ctorForInternal = ctorForPublic; + } + + if (ctorForPublic) + { + for (auto i : ctorForPublic->getParameters()) + { + publicCtorArgs.add({ i,nullptr }); + } + for (auto i : ctorForInternal->getParameters()) + { + publicInternalCtorArgs.add({ i,nullptr }); + publicInternalPrivateCtorArgs.add({ i,nullptr }); + } + } + } + + + // If we have a internal field which is not default-initialized we cannot allow + // a (1:1 element) ctor for public members (public member-wise ctor) to synthesize. + // This principal also applies for private members and internal/public member-wise ctor synthisis. + DeclVisibility maxVisibilityCtorToGenerate = getDeclVisibility(structDecl); + for (auto varDeclRef : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) + { + auto varDecl = varDeclRef.getDecl(); + ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); + + // Do not map a read-only variable for default-init + if (!getTypeForDeclRef(m_astBuilder, varDeclRef, varDeclRef.getLoc()).isLeftValue) + continue; + + auto declVisibility = getDeclVisibility(varDecl); + switch (declVisibility) + { + case DeclVisibility::Private: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + if (!varDecl->initExpr) + maxVisibilityCtorToGenerate = DeclVisibility::Private; + break; + case DeclVisibility::Internal: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + publicInternalCtorArgs.add({ varDecl, nullptr }); + if (!varDecl->initExpr) + maxVisibilityCtorToGenerate = DeclVisibility::Internal; + break; + case DeclVisibility::Public: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + publicInternalCtorArgs.add({ varDecl, nullptr }); + publicCtorArgs.add({ varDecl, nullptr }); + break; + default: + // Unknown visibility + SLANG_ASSERT(false); + break; + } + } + + List generatedMemberwiseCtors; + if (maxVisibilityCtorToGenerate >= DeclVisibility::Public) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public)) + generatedMemberwiseCtors.add(generatedCtor); + if (maxVisibilityCtorToGenerate >= DeclVisibility::Internal) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal)) + generatedMemberwiseCtors.add(generatedCtor); + if (maxVisibilityCtorToGenerate >= DeclVisibility::Private) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalPrivateCtorArgs), ctorList, structDecl, DeclVisibility::Private)) + generatedMemberwiseCtors.add(generatedCtor); + + // `checkIfCStyleStruct` must check after we add all possible Ctors. + // If we are a CStyleStruct add DefaultConstructExpr to all params (excluding arg 0) + bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); + if (isCStyleStruct && generatedMemberwiseCtors.getCount() > 0) + { + // We know the user provided 0 non-default ctor's, we only had a chance to generate non default Ctors above in this AST pass. + SLANG_ASSERT(generatedMemberwiseCtors.getCount() == 1); + for (auto generatedCtor : generatedMemberwiseCtors) + { + Index paramIndex = 0; + for (ParamDecl* i : generatedCtor->getParameters()) + { + // Never annotate the first parameter to prevent conflict with "DefaultCtor" + if (paramIndex == 0) + { + paramIndex++; + continue; + } + paramIndex++; + i->initExpr = createDefaultConstructExprForType(this->getASTBuilder(), (QualType)i->type, i->loc); + } + } + } + } checkAggTypeConformance(aggTypeDecl); } @@ -10539,224 +10758,8 @@ namespace Slang this, funcDecl, attr, DeclAssociationKind::PrimalSubstituteFunc); } - // Annotate ctor as a memberwise ctor. A non synthisized function may be annotated as a memberwise ctor - // if it has a compatible parameter list with a memberwise ctor. - void _annotateMemberwiseCtorWithVisibility(ConstructorDecl* ctor, DeclVisibility visibility) - { - switch (visibility) - { - case DeclVisibility::Public: - ctor->addOption(ConstructorTags::MemberwiseCtorForPublicVisibility); - break; - case DeclVisibility::Internal: - ctor->addOption(ConstructorTags::MemberwiseCtorForInternalVisibility); - break; - default: - break; - } - } - - static ConstructorDecl* _tryToGenerateCtorWithArgList( - SemanticsDeclVisitorBase* visitor, - ASTBuilder* astBuilder, - List&& args, - List& existingCtorList, - StructDecl* structDecl, - DeclVisibility visibility) - { - // Find any existing ctor type conflicts - for(auto ctor : existingCtorList) - { - auto existingCtorArgs = ctor->getParameters(); - auto existingCtorArgsLength = ctor->getParameters().getCount(); - auto newCtorArgsLength = args.getCount(); - - // Different arg count, ctor are not conflicting - if(existingCtorArgsLength != newCtorArgsLength) - continue; - - // if both arg lists are empty, return, we cannot have 2 default ctor's - if (!existingCtorArgsLength && !newCtorArgsLength) - return nullptr; - - // Check if every newCtorArg[i] is castable to existingCtorArg[i] (if so this is a conflicting ctor) - bool equalCtor = true; - for(Index i = 0; i < newCtorArgsLength; i++) - { - auto newCtorArg = args[i].m_argToCopy; - auto existingCtorArg = existingCtorArgs[i]; - if (visitor->getConversionCost(newCtorArg->getType(), existingCtorArg->getType()) == kConversionCost_Impossible) - { - equalCtor = false; - break; - } - } - if (equalCtor) - { - _annotateMemberwiseCtorWithVisibility(ctor, visibility); - return nullptr; - } - } - - // We did not have any ctor conflicts, auto-generate a ctor - auto generatedCtor = _createCtor(visitor, astBuilder, structDecl, std::move(args), visibility); - existingCtorList.add(generatedCtor); - _annotateMemberwiseCtorWithVisibility(generatedCtor, visibility); - return generatedCtor; - } - void SemanticsDeclAttributesVisitor::visitStructDecl(StructDecl* structDecl) { - // Add an empty default-ctor if missing a real default-ctor. - ConstructorDecl* defaultCtor = nullptr; - List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); - if (!defaultCtor) - { - defaultCtor = _createCtor(this, m_astBuilder, structDecl, {}, getDeclVisibility(structDecl)); - ctorList.add(defaultCtor); - } - - // Add auto-diff modifiers to $ZeroInit - if (auto zeroInitFunc = findZeroInitListFunc(structDecl)) - { - // Since we are zero-initializing, we are effectively `TreatAsDifferentiableAttribute`. - // This is important since some prior use-cases have no_diff on our `$ZeroInit` use-cases. - addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); - addModifier(zeroInitFunc, m_astBuilder->create()); - } - - // Add an empty constructor for all combinations of visibility and access - // which is possible: - // 1. public constructor - usable *outside class scope* in a *different module* - List publicCtorArgs; - // 2. public-internal constructor - usable *outside class scope* in the *same module* - List publicInternalCtorArgs; - // 3. public-private-internal constructor - usable *inside class scope* in the *same module* - List publicInternalPrivateCtorArgs; - - // Harvest parameters which map to the base type ctor. - // Note: assumes 1 structDecl, N number inheritance decl - for (auto inheritanceMember : structDecl->getMembersOfType()) - { - auto declRefType = as(inheritanceMember->base.type); - if (!declRefType) - continue; - auto baseStruct = as(declRefType->getDeclRef().getDecl()); - if (!baseStruct) - continue; - - DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; - - ConstructorDecl* ctorForPublic = nullptr; - ConstructorDecl* ctorForInternal = nullptr; - - // From our synthisized ctor's find the publicMemberCtor and internalMemberCtor. - List baseCtorList = _getCtorList(this->getASTBuilder(), this, baseStruct, nullptr); - for (auto i : baseCtorList) - { - if (i->containsOption(ConstructorTags::MemberwiseCtorForPublicVisibility)) - ctorForPublic = i; - if (i->containsOption(ConstructorTags::MemberwiseCtorForInternalVisibility)) - ctorForInternal = i; - } - - // If base is not defined in the same module (or if the internal ctor is missing) - // set the parameter list to a base-type member-wise ctor. - if (baseVisibilityToDerived == DeclVisibility::Public - || !ctorForInternal) - { - ctorForInternal = ctorForPublic; - } - - if (ctorForPublic) - { - for (auto i : ctorForPublic->getParameters()) - { - publicCtorArgs.add({ i,nullptr }); - } - for (auto i : ctorForInternal->getParameters()) - { - publicInternalCtorArgs.add({ i,nullptr }); - publicInternalPrivateCtorArgs.add({ i,nullptr }); - } - } - } - - - // If we have a internal field which is not default-initialized we cannot allow - // a (1:1 element) ctor for public members (public member-wise ctor) to synthesize. - // This principal also applies for private members and internal/public member-wise ctor synthisis. - DeclVisibility maxVisibilityCtorToGenerate = getDeclVisibility(structDecl); - for(auto varDeclRef : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) - { - auto varDecl = varDeclRef.getDecl(); - ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); - - // Do not map a read-only variable for default-init - if (!getTypeForDeclRef(m_astBuilder, varDeclRef, varDeclRef.getLoc()).isLeftValue) - continue; - - auto declVisibility = getDeclVisibility(varDecl); - switch (declVisibility) - { - case DeclVisibility::Private: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - if(!varDecl->initExpr) - maxVisibilityCtorToGenerate = DeclVisibility::Private; - break; - case DeclVisibility::Internal: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - publicInternalCtorArgs.add({ varDecl, nullptr }); - if (!varDecl->initExpr) - maxVisibilityCtorToGenerate = DeclVisibility::Internal; - break; - case DeclVisibility::Public: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - publicInternalCtorArgs.add({ varDecl, nullptr }); - publicCtorArgs.add({ varDecl, nullptr }); - break; - default: - // Unknown visibility - SLANG_ASSERT(false); - break; - } - } - - List generatedMemberwiseCtors; - if (maxVisibilityCtorToGenerate >= DeclVisibility::Public) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public)) - generatedMemberwiseCtors.add(generatedCtor); - if (maxVisibilityCtorToGenerate >= DeclVisibility::Internal) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal)) - generatedMemberwiseCtors.add(generatedCtor); - if (maxVisibilityCtorToGenerate >= DeclVisibility::Private) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalPrivateCtorArgs), ctorList, structDecl, DeclVisibility::Private)) - generatedMemberwiseCtors.add(generatedCtor); - - // `checkIfCStyleStruct` must check after we add all possible Ctors. - // If we are a CStyleStruct add DefaultConstructExpr to all params (excluding arg 0) - bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); - if (isCStyleStruct && generatedMemberwiseCtors.getCount() > 0) - { - // We know the user provided 0 non-default ctor's, we only had a chance to generate non default Ctors above in this AST pass. - SLANG_ASSERT(generatedMemberwiseCtors.getCount() == 1); - for (auto generatedCtor : generatedMemberwiseCtors) - { - Index paramIndex = 0; - for (ParamDecl* i : generatedCtor->getParameters()) - { - // Never annotate the first parameter to prevent conflict with "DefaultCtor" - if (paramIndex == 0) - { - paramIndex++; - continue; - } - paramIndex++; - i->initExpr = createDefaultConstructExprForType(this->getASTBuilder(), (QualType)i->type, i->loc); - } - } - } - int backingWidth = 0; [[maybe_unused]] int totalWidth = 0; diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp index 5dd63ac6cc..ffce308bc5 100644 --- a/source/slang/slang-ir-specialize-resources.cpp +++ b/source/slang/slang-ir-specialize-resources.cpp @@ -314,11 +314,6 @@ struct ResourceOutputSpecializationPass specializeCallSite(oldCall, newFunc, funcInfo); } specializedFuncs.add(oldFunc); - - // Since we can no longer fail and we are replacing all `Func` uses of 'KeepAlive'. - // This is done so DCE can clean-up our unspecialized version of our function. - if(auto keepAliveDecoration = oldFunc->findDecoration()) - keepAliveDecoration->removeAndDeallocate(); return true; } diff --git a/tests/language-feature/extensions/this-in-extension.slang b/tests/language-feature/extensions/this-in-extension.slang index 374eabe6fb..8482fe12bc 100644 --- a/tests/language-feature/extensions/this-in-extension.slang +++ b/tests/language-feature/extensions/this-in-extension.slang @@ -6,22 +6,28 @@ interface IFoo { - static const This identity; + static const This identityZero; + static const This identityFive; } __generic extension T { - This getIdentity() + This getIdentityZero() { - return identity; + return identityZero; + } + This getIdentityFive() + { + return identityFive; } } struct FooImpl : IFoo { int v = 1; - static const This identity = This(); + static const This identityZero = This(); + static const This identityFive = This(5); } @@ -32,7 +38,10 @@ RWStructuredBuffer outputBuffer; void computeMain(int3 dispatchThreadID : SV_DispatchThreadID) { FooImpl foo; - var ident = foo.getIdentity(); + var i0 = foo.getIdentityZero(); + var i5 = foo.getIdentityFive(); // CHECK: 1 - outputBuffer[0] = ident.v; + outputBuffer[0] = i0.v; + // CHECK: 5 + outputBuffer[0] = i5.v; } From 763055bebf8aafbe7e3291a9716a1d2d44d2e695 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 4 Sep 2024 10:50:12 -0400 Subject: [PATCH 067/100] changes: 1. move $ZeroInit definition to same pass as other functions --- source/slang/slang-check-decl.cpp | 77 ++++++++++++++----------------- 1 file changed, 35 insertions(+), 42 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 035f12519a..1d9fa8c651 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1921,43 +1921,6 @@ namespace Slang structDecl->addMember(member); } checkVisibility(structDecl); - - // Generate $ZeroInit. Since this is a place-holder non-ctor, we can pre-generate this function early. - // Note: some modfiers cannot be added at this stage, these will be added later in our AST passes. - if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getFirstOrNull()) - { - // $ZeroInit is a synthisized static-function only used In 2 cases: - // 1. if `{}` is used inside a `__init()` - // 2. if `{}` is used and a user has a 'synthisized __init()` - // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. - auto zeroInitFunc = m_astBuilder->create(); - auto ctorName = getName("$ZeroInit"); - zeroInitFunc->ownedScope = m_astBuilder->create(); - zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; - zeroInitFunc->ownedScope->parent = getScope(structDecl); - zeroInitFunc->parentDecl = structDecl; - zeroInitFunc->loc = structDecl->loc; - zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; - zeroInitFunc->nameAndLoc.name = ctorName; - zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; - zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); - auto body = m_astBuilder->create(); - body->scopeDecl = m_astBuilder->create(); - body->scopeDecl->ownedScope = m_astBuilder->create(); - body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); - body->scopeDecl->parentDecl = zeroInitFunc; - body->scopeDecl->loc = zeroInitFunc->loc; - body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; - body->closingSourceLoc = zeroInitFunc->closingSourceLoc; - zeroInitFunc->body = body; - body->body = m_astBuilder->create(); - - addModifier(zeroInitFunc, m_astBuilder->create()); - addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); - addModifier(zeroInitFunc, m_astBuilder->create()); - structDecl->addMember(zeroInitFunc); - } - } void SemanticsDeclHeaderVisitor::visitClassDecl(ClassDecl* classDecl) @@ -2629,13 +2592,43 @@ namespace Slang ctorList.add(defaultCtor); } - // Add auto-diff modifiers to $ZeroInit - if (auto zeroInitFunc = findZeroInitListFunc(structDecl)) - { - // Since we are zero-initializing, we are effectively `TreatAsDifferentiableAttribute`. - // This is important since some prior use-cases have no_diff on our `$ZeroInit` use-cases. + // Generate $ZeroInit. Since this is a place-holder non-ctor, we can pre-generate this function early. + // Note: some modfiers cannot be added at this stage, these will be added later in our AST passes. + if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getFirstOrNull()) + { + // $ZeroInit is a synthisized static-function only used In 2 cases: + // 1. if `{}` is used inside a `__init()` + // 2. if `{}` is used and a user has a 'synthisized __init()` + // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. + auto zeroInitFunc = m_astBuilder->create(); + auto ctorName = getName("$ZeroInit"); + zeroInitFunc->ownedScope = m_astBuilder->create(); + zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; + zeroInitFunc->ownedScope->parent = getScope(structDecl); + zeroInitFunc->parentDecl = structDecl; + zeroInitFunc->loc = structDecl->loc; + zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; + zeroInitFunc->nameAndLoc.name = ctorName; + zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; + zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); + auto body = m_astBuilder->create(); + body->scopeDecl = m_astBuilder->create(); + body->scopeDecl->ownedScope = m_astBuilder->create(); + body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); + body->scopeDecl->parentDecl = zeroInitFunc; + body->scopeDecl->loc = zeroInitFunc->loc; + body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; + body->closingSourceLoc = zeroInitFunc->closingSourceLoc; + zeroInitFunc->body = body; + body->body = m_astBuilder->create(); + addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); addModifier(zeroInitFunc, m_astBuilder->create()); + + addModifier(zeroInitFunc, m_astBuilder->create()); + addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); + addModifier(zeroInitFunc, m_astBuilder->create()); + structDecl->addMember(zeroInitFunc); } // Add an empty constructor for all combinations of visibility and access From d3a6604fdf9569bef31da4ebdae24ae867de3872 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 4 Sep 2024 10:53:32 -0400 Subject: [PATCH 068/100] clean up not-needed changes --- source/slang/slang-ir-specialize-resources.cpp | 1 + tests/autodiff/auto-differential-type.slang | 4 ++-- tests/autodiff/differential-method-synthesis.slang | 2 +- tests/autodiff/getter-setter-multi.slang | 6 +++--- tests/autodiff/make-struct-mixed-type.slang | 4 +--- tests/autodiff/reverse-addr-eliminate.slang | 4 +--- tests/metal/sv_target-complex-1.slang | 2 +- tests/pipeline/rasterization/mesh/passing-outputs.slang | 6 +++--- tests/spirv/pointer.slang | 2 +- 9 files changed, 14 insertions(+), 17 deletions(-) diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp index ffce308bc5..5e15098d42 100644 --- a/source/slang/slang-ir-specialize-resources.cpp +++ b/source/slang/slang-ir-specialize-resources.cpp @@ -309,6 +309,7 @@ struct ResourceOutputSpecializationPass // There should be no conditions at call sites that can cause specialization to // fail, because specialization does not depend on what is passed *in* to each // call, but only on what gets passed *out*. + // for( auto oldCall : calls ) { specializeCallSite(oldCall, newFunc, funcInfo); diff --git a/tests/autodiff/auto-differential-type.slang b/tests/autodiff/auto-differential-type.slang index c0ba030782..a253a25bb5 100644 --- a/tests/autodiff/auto-differential-type.slang +++ b/tests/autodiff/auto-differential-type.slang @@ -50,8 +50,8 @@ A f(A a) void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) { { - A a = { 1.0, 2.0 }; - A.Differential b = {0.2, 0}; + A a = {1.0, 2.0}; + A.Differential b = {0.2}; dpA dpa = dpA(a, b); diff --git a/tests/autodiff/differential-method-synthesis.slang b/tests/autodiff/differential-method-synthesis.slang index aab92afb53..e9385b78c1 100644 --- a/tests/autodiff/differential-method-synthesis.slang +++ b/tests/autodiff/differential-method-synthesis.slang @@ -39,7 +39,7 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) { { A a = {1.0, 2.0}; - A.Differential b = {0.2, 0}; + A.Differential b = {0.2}; dpA dpa = dpA(a, b); outputBuffer[0] = __fwd_diff(f)(dpa).d.b.x; // Expect: 0 outputBuffer[1] = A.dadd(b, b).b.x; // Expect: 0.4 diff --git a/tests/autodiff/getter-setter-multi.slang b/tests/autodiff/getter-setter-multi.slang index 85d4c7c64e..3f8257897f 100644 --- a/tests/autodiff/getter-setter-multi.slang +++ b/tests/autodiff/getter-setter-multi.slang @@ -23,21 +23,21 @@ struct A : IDifferentiable [__unsafeForceInlineEarly] static Differential dzero() { - B b = {}; + B b = {0.0}; return b; } [__unsafeForceInlineEarly] static Differential dadd(Differential a, Differential b) { - B o = { a.z + b.z, {}}; + B o = {a.z + b.z}; return o; } [__unsafeForceInlineEarly] static Differential dmul(T a, Differential b) { - B o = { __realCast(a) * b.z, {}}; + B o = {__realCast(a) * b.z}; return o; } }; diff --git a/tests/autodiff/make-struct-mixed-type.slang b/tests/autodiff/make-struct-mixed-type.slang index 680852f420..bc966eff7b 100644 --- a/tests/autodiff/make-struct-mixed-type.slang +++ b/tests/autodiff/make-struct-mixed-type.slang @@ -27,10 +27,8 @@ float f(MixedType m) void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID) { MixedType v = { 0, 2.0 }; - MixedType.Differential dv = { 0.0, 0.0 }; - + MixedType.Differential dv = { 0.0 }; var p = diffPair(v, dv); __bwd_diff(f)(p, 1.0); outputBuffer[0] = p.d.field; - outputBuffer[1] = dv.noDiffField; } \ No newline at end of file diff --git a/tests/autodiff/reverse-addr-eliminate.slang b/tests/autodiff/reverse-addr-eliminate.slang index 33c5ba8bf3..49f34a6e35 100644 --- a/tests/autodiff/reverse-addr-eliminate.slang +++ b/tests/autodiff/reverse-addr-eliminate.slang @@ -53,9 +53,7 @@ A f(A a, int i) [numthreads(1, 1, 1)] void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) { - A a = {}; - a.x = 1; - a.y = 2; + A a = {1.0, 2.0}; var dpa = diffPair(a); diff --git a/tests/metal/sv_target-complex-1.slang b/tests/metal/sv_target-complex-1.slang index f21b417ca6..a830ff3d26 100644 --- a/tests/metal/sv_target-complex-1.slang +++ b/tests/metal/sv_target-complex-1.slang @@ -30,5 +30,5 @@ struct Output [shader("fragment")] Output fragmentMain() { - return { float4(1), { float4(2) }, float4(3), {} }; + return { float4(1), {float4(2)}, float4(3) }; } \ No newline at end of file diff --git a/tests/pipeline/rasterization/mesh/passing-outputs.slang b/tests/pipeline/rasterization/mesh/passing-outputs.slang index 80595c4564..45d9405ab1 100644 --- a/tests/pipeline/rasterization/mesh/passing-outputs.slang +++ b/tests/pipeline/rasterization/mesh/passing-outputs.slang @@ -30,17 +30,17 @@ struct Vertex void everything(OutputVertices vs) { - vs[0] = { float4(0), float3(1), {} }; + vs[0] = {float4(0), float3(1)}; } void just_one(out Vertex v) { - v = { float4(0), float3(1), {} }; + v = {float4(0), float3(1)}; } void just_two(out Vertex v, out Vertex w) { - v = { float4(0), float3(1), {} }; + v = {float4(0), float3(1)}; w = v; } diff --git a/tests/spirv/pointer.slang b/tests/spirv/pointer.slang index 51d26f47df..03ca3fb394 100644 --- a/tests/spirv/pointer.slang +++ b/tests/spirv/pointer.slang @@ -39,7 +39,7 @@ void main(int id : SV_DispatchThreadID) *pData1 = 3; *(int2*)pData = int2(1, 2); pData1[-1] = 2; - buffer[0].pNext[1] = {5, 0}; + buffer[0].pNext[1] = {5}; // CHECK: OpConvertPtrToU // CHECK: OpINotEqual if (pData1) From 1281459a790dd2664cef39e8b78bc3e889b0a8b1 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:00:37 -0400 Subject: [PATCH 069/100] clean up more unneeded overload logic --- source/slang/slang-check-overload.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index fb0fed6d50..ee0c45e070 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -1191,10 +1191,6 @@ namespace Slang LookupResultItem const& left, LookupResultItem const& right) { - // Equal lookup-items, choose the left one. - if (left.declRef == right.declRef) - return 1; - // It is possible for lookup to return both an interface requirement // and the concrete function that satisfies that requirement. // We always want to favor a concrete method over an interface @@ -1455,10 +1451,7 @@ namespace Slang return overloadRankDiff; } - // Since some overload logic requires a simplified overload item list - // we require some comparison to remove clearly invalid overload candidates - // to avoid errors. - return CompareLookupResultItems(left->item, right->item); + return 0; } void SemanticsVisitor::AddOverloadCandidateInner( From 964c3e5cab497fed5d79cf857c417c388f900647 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:52:36 -0400 Subject: [PATCH 070/100] change around how we define ctor and zeroInit to be more flexable --- source/slang/slang-ast-support-types.h | 3 +- source/slang/slang-check-decl.cpp | 304 +++++++++++++------------ source/slang/slang-check-expr.cpp | 1 - 3 files changed, 154 insertions(+), 154 deletions(-) diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index d396f39c38..e3c88436b5 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -490,8 +490,7 @@ namespace Slang CanUseFuncSignature = ReadyForReference, CanSpecializeGeneric = ReadyForReference, CanReadInterfaceRequirements = ReadyForLookup, - CanUseZeroInit = SignatureChecked, - DefaultConstructorReadyForUse = AttributesChecked, + DefaultConstructorReadyForUse = ReadyForConformances, VarInitExprAreChecked = DefinitionChecked, }; diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 1d9fa8c651..e398df7c9f 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2583,182 +2583,184 @@ namespace Slang { if (auto structDecl = as(aggTypeDecl)) { - // Add an empty default-ctor if missing a real default-ctor. - ConstructorDecl* defaultCtor = nullptr; - List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); - if (!defaultCtor) - { - defaultCtor = _createCtor(this, m_astBuilder, structDecl, {}, getDeclVisibility(structDecl)); - ctorList.add(defaultCtor); - } - - // Generate $ZeroInit. Since this is a place-holder non-ctor, we can pre-generate this function early. - // Note: some modfiers cannot be added at this stage, these will be added later in our AST passes. if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getFirstOrNull()) { - // $ZeroInit is a synthisized static-function only used In 2 cases: - // 1. if `{}` is used inside a `__init()` - // 2. if `{}` is used and a user has a 'synthisized __init()` - // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. - auto zeroInitFunc = m_astBuilder->create(); - auto ctorName = getName("$ZeroInit"); - zeroInitFunc->ownedScope = m_astBuilder->create(); - zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; - zeroInitFunc->ownedScope->parent = getScope(structDecl); - zeroInitFunc->parentDecl = structDecl; - zeroInitFunc->loc = structDecl->loc; - zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; - zeroInitFunc->nameAndLoc.name = ctorName; - zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; - zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); - auto body = m_astBuilder->create(); - body->scopeDecl = m_astBuilder->create(); - body->scopeDecl->ownedScope = m_astBuilder->create(); - body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); - body->scopeDecl->parentDecl = zeroInitFunc; - body->scopeDecl->loc = zeroInitFunc->loc; - body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; - body->closingSourceLoc = zeroInitFunc->closingSourceLoc; - zeroInitFunc->body = body; - body->body = m_astBuilder->create(); - - addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); - addModifier(zeroInitFunc, m_astBuilder->create()); - - addModifier(zeroInitFunc, m_astBuilder->create()); - addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); - addModifier(zeroInitFunc, m_astBuilder->create()); - structDecl->addMember(zeroInitFunc); - } - - // Add an empty constructor for all combinations of visibility and access - // which is possible: - // 1. public constructor - usable *outside class scope* in a *different module* - List publicCtorArgs; - // 2. public-internal constructor - usable *outside class scope* in the *same module* - List publicInternalCtorArgs; - // 3. public-private-internal constructor - usable *inside class scope* in the *same module* - List publicInternalPrivateCtorArgs; - - // Harvest parameters which map to the base type ctor. - // Note: assumes 1 structDecl, N number inheritance decl - for (auto inheritanceMember : structDecl->getMembersOfType()) - { - auto declRefType = as(inheritanceMember->base.type); - if (!declRefType) - continue; - auto baseStruct = as(declRefType->getDeclRef().getDecl()); - if (!baseStruct) - continue; - - DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; - - ConstructorDecl* ctorForPublic = nullptr; - ConstructorDecl* ctorForInternal = nullptr; - - // From our synthisized ctor's find the publicMemberCtor and internalMemberCtor. - List baseCtorList = _getCtorList(this->getASTBuilder(), this, baseStruct, nullptr); - for (auto i : baseCtorList) + // Add an empty default-ctor if missing a real default-ctor. + ConstructorDecl* defaultCtor = nullptr; + List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); + if (!defaultCtor) { - if (i->containsOption(ConstructorTags::MemberwiseCtorForPublicVisibility)) - ctorForPublic = i; - if (i->containsOption(ConstructorTags::MemberwiseCtorForInternalVisibility)) - ctorForInternal = i; + defaultCtor = _createCtor(this, m_astBuilder, structDecl, {}, getDeclVisibility(structDecl)); + ctorList.add(defaultCtor); } - // If base is not defined in the same module (or if the internal ctor is missing) - // set the parameter list to a base-type member-wise ctor. - if (baseVisibilityToDerived == DeclVisibility::Public - || !ctorForInternal) + // Add auto-diff modifiers to $ZeroInit + if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getFirstOrNull()) { - ctorForInternal = ctorForPublic; + // $ZeroInit is a synthisized static-function only used In 2 cases: + // 1. if `{}` is used inside a `__init()` + // 2. if `{}` is used and a user has a 'synthisized __init()` + // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. + auto zeroInitFunc = m_astBuilder->create(); + auto ctorName = getName("$ZeroInit"); + zeroInitFunc->ownedScope = m_astBuilder->create(); + zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; + zeroInitFunc->ownedScope->parent = getScope(structDecl); + zeroInitFunc->parentDecl = structDecl; + zeroInitFunc->loc = structDecl->loc; + zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; + zeroInitFunc->nameAndLoc.name = ctorName; + zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; + zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); + auto body = m_astBuilder->create(); + body->scopeDecl = m_astBuilder->create(); + body->scopeDecl->ownedScope = m_astBuilder->create(); + body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); + body->scopeDecl->parentDecl = zeroInitFunc; + body->scopeDecl->loc = zeroInitFunc->loc; + body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; + body->closingSourceLoc = zeroInitFunc->closingSourceLoc; + zeroInitFunc->body = body; + body->body = m_astBuilder->create(); + + addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); + addModifier(zeroInitFunc, m_astBuilder->create()); + + addModifier(zeroInitFunc, m_astBuilder->create()); + addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); + addModifier(zeroInitFunc, m_astBuilder->create()); + structDecl->addMember(zeroInitFunc); } - if (ctorForPublic) + // Add an empty constructor for all combinations of visibility and access + // which is possible: + // 1. public constructor - usable *outside class scope* in a *different module* + List publicCtorArgs; + // 2. public-internal constructor - usable *outside class scope* in the *same module* + List publicInternalCtorArgs; + // 3. public-private-internal constructor - usable *inside class scope* in the *same module* + List publicInternalPrivateCtorArgs; + + // Harvest parameters which map to the base type ctor. + // Note: assumes 1 structDecl, N number inheritance decl + for (auto inheritanceMember : structDecl->getMembersOfType()) { - for (auto i : ctorForPublic->getParameters()) + auto declRefType = as(inheritanceMember->base.type); + if (!declRefType) + continue; + auto baseStruct = as(declRefType->getDeclRef().getDecl()); + if (!baseStruct) + continue; + + DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; + + ConstructorDecl* ctorForPublic = nullptr; + ConstructorDecl* ctorForInternal = nullptr; + + // From our synthisized ctor's find the publicMemberCtor and internalMemberCtor. + List baseCtorList = _getCtorList(this->getASTBuilder(), this, baseStruct, nullptr); + for (auto i : baseCtorList) { - publicCtorArgs.add({ i,nullptr }); + if (i->containsOption(ConstructorTags::MemberwiseCtorForPublicVisibility)) + ctorForPublic = i; + if (i->containsOption(ConstructorTags::MemberwiseCtorForInternalVisibility)) + ctorForInternal = i; } - for (auto i : ctorForInternal->getParameters()) + + // If base is not defined in the same module (or if the internal ctor is missing) + // set the parameter list to a base-type member-wise ctor. + if (baseVisibilityToDerived == DeclVisibility::Public + || !ctorForInternal) { - publicInternalCtorArgs.add({ i,nullptr }); - publicInternalPrivateCtorArgs.add({ i,nullptr }); + ctorForInternal = ctorForPublic; + } + + if (ctorForPublic) + { + for (auto i : ctorForPublic->getParameters()) + { + publicCtorArgs.add({ i,nullptr }); + } + for (auto i : ctorForInternal->getParameters()) + { + publicInternalCtorArgs.add({ i,nullptr }); + publicInternalPrivateCtorArgs.add({ i,nullptr }); + } } } - } - // If we have a internal field which is not default-initialized we cannot allow - // a (1:1 element) ctor for public members (public member-wise ctor) to synthesize. - // This principal also applies for private members and internal/public member-wise ctor synthisis. - DeclVisibility maxVisibilityCtorToGenerate = getDeclVisibility(structDecl); - for (auto varDeclRef : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) - { - auto varDecl = varDeclRef.getDecl(); - ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); + // If we have a internal field which is not default-initialized we cannot allow + // a (1:1 element) ctor for public members (public member-wise ctor) to synthesize. + // This principal also applies for private members and internal/public member-wise ctor synthisis. + DeclVisibility maxVisibilityCtorToGenerate = getDeclVisibility(structDecl); + for (auto varDeclRef : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) + { + auto varDecl = varDeclRef.getDecl(); + ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); - // Do not map a read-only variable for default-init - if (!getTypeForDeclRef(m_astBuilder, varDeclRef, varDeclRef.getLoc()).isLeftValue) - continue; + // Do not map a read-only variable for default-init + if (!getTypeForDeclRef(m_astBuilder, varDeclRef, varDeclRef.getLoc()).isLeftValue) + continue; - auto declVisibility = getDeclVisibility(varDecl); - switch (declVisibility) - { - case DeclVisibility::Private: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - if (!varDecl->initExpr) - maxVisibilityCtorToGenerate = DeclVisibility::Private; - break; - case DeclVisibility::Internal: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - publicInternalCtorArgs.add({ varDecl, nullptr }); - if (!varDecl->initExpr) - maxVisibilityCtorToGenerate = DeclVisibility::Internal; - break; - case DeclVisibility::Public: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - publicInternalCtorArgs.add({ varDecl, nullptr }); - publicCtorArgs.add({ varDecl, nullptr }); - break; - default: - // Unknown visibility - SLANG_ASSERT(false); - break; + auto declVisibility = getDeclVisibility(varDecl); + switch (declVisibility) + { + case DeclVisibility::Private: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + if (!varDecl->initExpr) + maxVisibilityCtorToGenerate = DeclVisibility::Private; + break; + case DeclVisibility::Internal: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + publicInternalCtorArgs.add({ varDecl, nullptr }); + if (!varDecl->initExpr) + maxVisibilityCtorToGenerate = DeclVisibility::Internal; + break; + case DeclVisibility::Public: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + publicInternalCtorArgs.add({ varDecl, nullptr }); + publicCtorArgs.add({ varDecl, nullptr }); + break; + default: + // Unknown visibility + SLANG_ASSERT(false); + break; + } } - } - List generatedMemberwiseCtors; - if (maxVisibilityCtorToGenerate >= DeclVisibility::Public) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public)) - generatedMemberwiseCtors.add(generatedCtor); - if (maxVisibilityCtorToGenerate >= DeclVisibility::Internal) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal)) - generatedMemberwiseCtors.add(generatedCtor); - if (maxVisibilityCtorToGenerate >= DeclVisibility::Private) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalPrivateCtorArgs), ctorList, structDecl, DeclVisibility::Private)) - generatedMemberwiseCtors.add(generatedCtor); - - // `checkIfCStyleStruct` must check after we add all possible Ctors. - // If we are a CStyleStruct add DefaultConstructExpr to all params (excluding arg 0) - bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); - if (isCStyleStruct && generatedMemberwiseCtors.getCount() > 0) - { - // We know the user provided 0 non-default ctor's, we only had a chance to generate non default Ctors above in this AST pass. - SLANG_ASSERT(generatedMemberwiseCtors.getCount() == 1); - for (auto generatedCtor : generatedMemberwiseCtors) + List generatedMemberwiseCtors; + if (maxVisibilityCtorToGenerate >= DeclVisibility::Public) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public)) + generatedMemberwiseCtors.add(generatedCtor); + if (maxVisibilityCtorToGenerate >= DeclVisibility::Internal) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal)) + generatedMemberwiseCtors.add(generatedCtor); + if (maxVisibilityCtorToGenerate >= DeclVisibility::Private) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalPrivateCtorArgs), ctorList, structDecl, DeclVisibility::Private)) + generatedMemberwiseCtors.add(generatedCtor); + + // `checkIfCStyleStruct` must check after we add all possible Ctors. + // If we are a CStyleStruct add DefaultConstructExpr to all params (excluding arg 0) + bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); + if (isCStyleStruct && generatedMemberwiseCtors.getCount() > 0) { - Index paramIndex = 0; - for (ParamDecl* i : generatedCtor->getParameters()) + // We know the user provided 0 non-default ctor's, we only had a chance to generate non default Ctors above in this AST pass. + SLANG_ASSERT(generatedMemberwiseCtors.getCount() == 1); + for (auto generatedCtor : generatedMemberwiseCtors) { - // Never annotate the first parameter to prevent conflict with "DefaultCtor" - if (paramIndex == 0) + Index paramIndex = 0; + for (ParamDecl* i : generatedCtor->getParameters()) { + // Never annotate the first parameter to prevent conflict with "DefaultCtor" + if (paramIndex == 0) + { + paramIndex++; + continue; + } paramIndex++; - continue; + i->initExpr = createDefaultConstructExprForType(this->getASTBuilder(), (QualType)i->type, i->loc); } - paramIndex++; - i->initExpr = createDefaultConstructExprForType(this->getASTBuilder(), (QualType)i->type, i->loc); } } } diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 05e3502d1f..fdac50ca6a 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -884,7 +884,6 @@ namespace Slang return DeclVisibility::Public; } - bool SemanticsVisitor::isVisibilityOfDeclVisibleInScope(DeclRef declRef, DeclVisibility visibility, Scope* scope) { if (visibility == DeclVisibility::Public) From 0e5e5ba2acede33f9db4db5c287bd30d17855422 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 4 Sep 2024 22:55:34 -0400 Subject: [PATCH 071/100] heavily document and comment on this PR in-case it is handed off to another team-member --- source/slang/diff.meta.slang | 4 + source/slang/hlsl.meta.slang | 4 + source/slang/slang-check-conversion.cpp | 27 ++-- source/slang/slang-check-decl.cpp | 122 ++++++++++++++---- source/slang/slang-ir.cpp | 10 ++ .../extensions/this-in-extension.slang | 2 +- 6 files changed, 133 insertions(+), 36 deletions(-) diff --git a/source/slang/diff.meta.slang b/source/slang/diff.meta.slang index 3a9c31b5eb..d6d9a7600e 100644 --- a/source/slang/diff.meta.slang +++ b/source/slang/diff.meta.slang @@ -1023,6 +1023,10 @@ struct DiffTensorView } }; +// Note: we need `TorchTensorType` so Slang is aware +// of when we use `TorchTensorType` in a synthisized +// function. This is important since `[CudaHost]` is +// required for any function using `TorchTensorType` /// Represents the handle of a Torch tensor object. __generic __intrinsic_type($(kIROp_TorchTensorType)) diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index d072ab834b..414cb2afe5 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -19962,6 +19962,10 @@ ${ case hlsl: uint isSingleLod = 0; + // Note: we cannot pass `Shape.dimensions` + // directly as a parameter into a Call, otherwise + // AST lookup fails (bug?), creating an intermediary works + // so we do this workaround. int shapeDim = Shape.dimensions; Footprint footprint = {__queryFootprint$(CoarseOrFine)NVAPI( shapeDim, diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 7483513903..483ee0b231 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -92,13 +92,10 @@ namespace Slang if(isEffectivelyScalarForInitializerLists(fromExpr->type)) return false; + // If 2 types are equal, we know the types can be coerced directly if (toType->equals(fromExpr->type)) return true; - // Once the above cases are handled, the main thing - // we want to check for is whether a direct initialization - // is possible (a type conversion exists). - // return false; } @@ -445,15 +442,18 @@ namespace Slang else if(auto toDeclRefType = as(toType)) { auto toTypeDeclRef = toDeclRefType->getDeclRef(); - // Trying to initialize a `struct` type given an initializer list. - // We will try to coerce the initializer list into a constructor. if(auto toStructDeclRef = toTypeDeclRef.as()) { - auto toStructDecl = toStructDeclRef.getDecl(); + // We will try to coerce the initializer list into a struct following these steps: + // 1. Ensure our `StructDecl` has declaratations created for all auto-generated constructors + // 2. We have a `{}` (0 arguments), try to coerce + // 3. We have a `{arg1, arg2...}`, try to coerce + auto toStructDecl = toStructDeclRef.getDecl(); + // 1. Ensure our `StructDecl` has declaratations created for all auto-generated constructors ensureDecl(toStructDecl, DeclCheckState::DefaultConstructorReadyForUse); - // Easy case of default constructor or equivalent + // 2. We have a `{}` (0 arguments), try to coerce if (argCount == 0) { if (outToExpr) @@ -464,10 +464,15 @@ namespace Slang return true; } + // 3. We have a `{arg1, arg2...}`, try to coerce + // + // For this situation we have more steps: + // a. Find constructor candidate for our particular init-list + // b. Collect and coerce init-list arguments into constructor parameters + // c. Create InvokeExpr for our valid ConstructorDecl List ctorList = _getCtorList(this->getASTBuilder(), this, toStructDecl, nullptr); bool allowCStyleInitList = checkIfCStyleStruct(this, toStructDecl); - // Non-default constructor case List maybeArgList; maybeArgList.reserve(argCount); Index ioArgIndexMirror = ioArgIndex; @@ -475,6 +480,8 @@ namespace Slang for (auto& ctor : ctorList) { + // a. Find constructor candidate for our particular init-list + // Don't try to init default ctor with this logic auto ctorParamCount = ctor->getParameters().getCount(); if (ctorParamCount == 0) @@ -488,6 +495,7 @@ namespace Slang if (!allowCStyleInitList && ctorParamCount != Index(argCount)) continue; + // b. Collect and coerce init-list arguments into constructor parameters List maybeCandidate; auto parameters = getParameters(m_astBuilder, ctor); auto parametersCount = parameters.getCount(); @@ -530,6 +538,7 @@ namespace Slang continue; } + // c. Create InvokeExpr for our valid ConstructorDecl // We cannot fail anymore, set ioArgIndex to the 'used up arg count'. if (outToExpr) { diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index e398df7c9f..2bb129bfa3 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1863,7 +1863,6 @@ namespace Slang ctor->addOption(ConstructorTags::Synthesized); // kIROp_TorchTensorType must only refer to its own type through Host functions - // TODO: figure-out how to pass CudaHost for when we have a nested TorchTensor. if(auto intrinsicType = decl->findModifier()) if(intrinsicType->irOp == kIROp_TorchTensorType) addModifier(ctor, m_astBuilder->create()); @@ -2563,6 +2562,12 @@ namespace Slang return generatedCtor; } + bool _structHasMemberWithValue(ASTBuilder* m_astBuilder, StructDecl* structDecl) + { + return getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance).getFirstOrNull() + || getMembersOfType(m_astBuilder, structDecl).getFirstOrNull(); + } + // Concretize interface conformances so that we have witnesses as required for lookup. // for lookup. struct SemanticsDeclConformancesVisitor @@ -2583,9 +2588,23 @@ namespace Slang { if (auto structDecl = as(aggTypeDecl)) { - if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getFirstOrNull()) + // Only generate declarations if we have something that should be taken into account (Inheritance/VarDecl) + if (_structHasMemberWithValue(getASTBuilder(), structDecl)) { - // Add an empty default-ctor if missing a real default-ctor. + // First part of auto-generating constructors/functions is inside `SemanticsDeclConformancesVisitor::visitAggTypeDecl` + // * Create declarations for constructors/functions. + // Second part of auto-generating constructors/functions is inside `SemanticsDeclBodyVisitor::visitAggTypeDecl` + // * Add bodies to our declarations + // + // These are split up so we can assign declarations before we finish definitions + // + // + // Steps: + // 1. Add an declaration for default-ctor if missing a real default-ctor. + // 2. Generate $ZeroInit + // 3. Generate 'member-wise' constructors + + // 1. Add an declaration for default-ctor if missing a real default-ctor. ConstructorDecl* defaultCtor = nullptr; List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); if (!defaultCtor) @@ -2594,8 +2613,8 @@ namespace Slang ctorList.add(defaultCtor); } - // Add auto-diff modifiers to $ZeroInit - if (getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance).getFirstOrNull()) + // 2. Generate $ZeroInit + if (_structHasMemberWithValue(getASTBuilder(), structDecl)) { // $ZeroInit is a synthisized static-function only used In 2 cases: // 1. if `{}` is used inside a `__init()` @@ -2632,13 +2651,16 @@ namespace Slang structDecl->addMember(zeroInitFunc); } + + // 3. Generate 'member-wise' constructors + // // Add an empty constructor for all combinations of visibility and access // which is possible: - // 1. public constructor - usable *outside class scope* in a *different module* + // public constructor - usable *outside class scope* in a *different module* List publicCtorArgs; - // 2. public-internal constructor - usable *outside class scope* in the *same module* + // public-internal constructor - usable *outside class scope* in the *same module* List publicInternalCtorArgs; - // 3. public-private-internal constructor - usable *inside class scope* in the *same module* + // public-private-internal constructor - usable *inside class scope* in the *same module* List publicInternalPrivateCtorArgs; // Harvest parameters which map to the base type ctor. @@ -2690,10 +2712,12 @@ namespace Slang } - // If we have a internal field which is not default-initialized we cannot allow - // a (1:1 element) ctor for public members (public member-wise ctor) to synthesize. + // If we have an internal field which lacks an initExpr we cannot allow + // a memberwise ctor to be synthesized for public members. // This principal also applies for private members and internal/public member-wise ctor synthisis. DeclVisibility maxVisibilityCtorToGenerate = getDeclVisibility(structDecl); + + // Here we collect all variables which will be apart of our member-wise ctor's. for (auto varDeclRef : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) { auto varDecl = varDeclRef.getDecl(); @@ -8054,9 +8078,17 @@ namespace Slang if (!structDecl) return; - auto structDeclType = DeclRefType::create(m_astBuilder, structDecl); + // First part of auto-generating constructors/functions is inside `SemanticsDeclConformancesVisitor::visitAggTypeDecl` + // * Create declarations for constructors/functions. + // Second part of auto-generating constructors/functions is inside `SemanticsDeclBodyVisitor::visitAggTypeDecl` + // * Add bodies to our declarations + // + // These are split up so we can assign declarations before we finish definitions + // + // - /// Collect ctor info + auto structDeclType = DeclRefType::create(m_astBuilder, structDecl); + // Collect ctor info struct DeclAndCtorInfo { AggTypeDecl* m_inheritanceBaseDecl; @@ -8105,8 +8137,8 @@ namespace Slang } DeclAndCtorInfo structDeclInfo = DeclAndCtorInfo(m_astBuilder, this, structDecl, nullptr, false); - /// ensure all varDecl members are processed up to SemanticsBodyVisitor so we can be sure that if init expressions - /// of members are to be synthisised, they are. + // ensure all varDecl members are processed up to SemanticsBodyVisitor so we can be sure that if init expressions + // of members are to be synthisised, they are. bool isDefaultInitializableType = isSubtype(structDeclType, m_astBuilder->getDefaultInitializableType(), IsSubTypeOptions::None); for (auto m : structDecl->members) { @@ -8122,7 +8154,13 @@ namespace Slang Dictionary cachedDeclToCheckedVar; - /// Insert 'this->base->__init()' into 'this->__init()'. + // Insert 'this->base->__init()' into 'this->__init()'. + /* + __init() + { + super::__init(); // we add this call here + } + */ for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { auto ctor = ctorInfo.m_ctor; @@ -8175,12 +8213,22 @@ namespace Slang seqStmt->stmts.insert(ctorInfo.m_insertOffset++, seqStmtChild); } - /// Collect all 'per instance' members of our struct + // Collect all 'per instance' members of our struct List> membersOfStructDeclInstance; for (auto i : getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance)) membersOfStructDeclInstance.add(i); - /// Assign member variable init expressions + // Assign member variable init expressions + /* + struct Foo + { + int a = 5; + __init() + { + a = 5; // we add this initExpr logic here. + } + } + */ for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { auto ctor = ctorInfo.m_ctor; @@ -8236,9 +8284,9 @@ namespace Slang seqStmt->stmts.insert(ctorInfo.m_insertOffset++, seqStmtChild); } - /// Note: we assume only 1 inheritance decl currently. - /// Pre-calculate if we have a base-type and its associated ctor-list - /// We also must ensure inheritance-decl is checked, else we may not have up-to-date 'DerivativeMemberAttribute' modifiers + // Note: we assume only 1 inheritance decl currently. + // Pre-calculate if we have a base-type and its associated ctor-list + // We also must ensure inheritance-decl is checked, else we may not have up-to-date 'DerivativeMemberAttribute' modifiers DeclAndCtorInfo* baseStructInfo = nullptr; for(auto& i : inheritanceInfoList) { @@ -8247,7 +8295,7 @@ namespace Slang baseStructInfo = &i; } - /// pre-calculate any requirements of a CudaHostAttribute + // pre-calculate any requirements of a CudaHostAttribute HashSet requiresCudaHostModifier; for (auto member : membersOfStructDeclInstance) if (containsTargetType(m_astBuilder, member.getDecl()->type.type)) @@ -8264,7 +8312,7 @@ namespace Slang - /// Insert parameters as values for member-wise init expression. + // Insert parameters as values for member-wise init expression. for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { auto ctor = ctorInfo.m_ctor; @@ -8292,6 +8340,14 @@ namespace Slang while (paramIndex < paramCount) { auto param = paramList[paramIndex]; + /* + 2 parts: + + 1. Insert super::__init inside this->__init() + 2. Assign *parameters* to related *varDecl member of our struct* + */ + + // Part 1 // If we have a base type, the first arg is a 'base->__init(...)'. We need to find this 'base->__init(...)' // and assign the parameters needed to call '__init(...)' if (paramIndex == 0 && baseStructInfo && baseStructInfo->m_ctorInfoList.getCount() > 0) @@ -8356,6 +8412,7 @@ namespace Slang } } + // Part 2 // Regular assignment logic paramIndex++; auto paramType = param->getType(); @@ -8408,7 +8465,7 @@ namespace Slang seqStmt->stmts.insert(ctorInfo.m_insertOffset++, seqStmtChild); } - /// Compiler generated ctor may be destroyed + // Compiler generated ctor may be destroyed bool destroyedDefaultCtor = false; if(structDeclInfo.m_defaultCtor && structDeclInfo.m_defaultCtor->containsOption(ConstructorTags::Synthesized)) @@ -8428,6 +8485,7 @@ namespace Slang } } + // Fill in our $ZeroInit if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) { SLANG_ASSERT(zeroInitListFunc->getParameters().getCount() == 0); @@ -8438,10 +8496,19 @@ namespace Slang SLANG_ASSERT(as(block->body)); auto seqStmt = as(block->body); + /* + 3 steps: + 1. Assign DefaultConstructExpr to `this` + 2. Insert `super::$ZeroInit()` into `this->$ZeroInit` + 3. Assign initExpr to all members + */ + bool foundCudaHostModifier = false; auto defaultConstructExpr = createDefaultConstructExprForType(m_astBuilder, structDeclType, seqStmt->loc); + // Part 1 + // Assign DefaultConstructExpr to `this` auto structVarDecl = m_astBuilder->create(); addModifier(structVarDecl, m_astBuilder->create()); structVarDecl->type = TypeExp(structDeclType); @@ -8466,12 +8533,14 @@ namespace Slang structAssignExprStmt->loc = seqStmt->loc; seqStmt->stmts.add(structAssignExprStmt); - // Assign $ZeroInit of inheritanceDecl + // Part 2 + // Insert `super::$ZeroInit()` into `this->$ZeroInit` + // Only insert if we have values to insert for if (baseStructInfo) { if (auto baseStructDecl = as(baseStructInfo->m_inheritanceBaseDecl)) { - if (getMembersOfType(m_astBuilder, baseStructDecl, MemberFilterStyle::Instance).getFirstOrNull()) + if (_structHasMemberWithValue(getASTBuilder(), structDecl)) { Expr* zeroInitFunc = constructZeroInitListFunc(this, baseStructDecl, baseStructInfo->m_inheritanceDecl->base.type, ConstructZeroInitListOptions::PreferZeroInitFunc); auto assign = m_astBuilder->create(); @@ -8485,7 +8554,8 @@ namespace Slang } } - // Assign initExpr to all members + // Part 3 + // Assign initExpr to all members of structDecl for (auto memberRef : membersOfStructDeclInstance) { diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 3ed317d1db..a7692f5a63 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -3738,6 +3738,14 @@ namespace Slang IRInst* IRBuilder::_emitDefaultConstruct(IRType* type, bool fallback, HashSet visitedTypes) { + // Slang generally detects recursive type-uses in IR, + // This means that DefaultConstruct may crash unless we + // track visited types with `visitedTypes.contains(type)` + // to avoid infinite looping of type-checks + // + // Slang may be asked to default init a `RWTexture2D`. + // If so, `isResourceType(type)` ensures we don't generate + // garbage/ if (visitedTypes.contains(type) || isResourceType(type)) return emitUndefined(type); visitedTypes.add(type); @@ -3865,10 +3873,12 @@ namespace Slang } return nullptr; } + IRInst* IRBuilder::emitDefaultConstruct(IRType* type, bool fallback) { return _emitDefaultConstruct(type, fallback, {}); } + IRInst* IRBuilder::emitEmbeddedDXIL(ISlangBlob *blob) { IRInst* args[] = { getBlobValue(blob) }; diff --git a/tests/language-feature/extensions/this-in-extension.slang b/tests/language-feature/extensions/this-in-extension.slang index 8482fe12bc..e3b5eea276 100644 --- a/tests/language-feature/extensions/this-in-extension.slang +++ b/tests/language-feature/extensions/this-in-extension.slang @@ -43,5 +43,5 @@ void computeMain(int3 dispatchThreadID : SV_DispatchThreadID) // CHECK: 1 outputBuffer[0] = i0.v; // CHECK: 5 - outputBuffer[0] = i5.v; + outputBuffer[1] = i5.v; } From 6d40ddc64881092e8bbd2d3f6028f2712627fb8a Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:10:46 -0400 Subject: [PATCH 072/100] fix merge error --- source/slang/slang-check-decl.cpp | 66 ---------------------- source/slang/slang-constructor-utility.cpp | 22 +------- 2 files changed, 3 insertions(+), 85 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index ad74ef292e..61ffcbc9bc 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1944,72 +1944,6 @@ namespace Slang return true; } - bool isDefaultInitializable(VarDeclBase* varDecl) - { - if (!DiagnoseIsAllowedInitExpr(varDecl, nullptr)) - return false; - - // Find struct and modifiers associated with varDecl - StructDecl* structDecl = as(varDecl); - if (auto declRefType = as(varDecl->getType())) - { - if (auto genericAppRefDecl = as(declRefType->getDeclRefBase())) - { - auto baseGenericRefType = genericAppRefDecl->getBase()->getDecl(); - if (auto baseTypeStruct = as(baseGenericRefType)) - { - structDecl = baseTypeStruct; - } - else if (auto genericDecl = as(baseGenericRefType)) - { - if(auto innerTypeStruct = as(genericDecl->inner)) - structDecl = innerTypeStruct; - } - } - } - if (structDecl) - { - // find if a type is non-copyable - if (structDecl->findModifier()) - return false; - } - - return true; - } - - static Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, VarDeclBase* varDecl) - { - if (!varDecl->type || !varDecl->type.type) - return nullptr; - - if (!isDefaultInitializable(varDecl)) - return nullptr; - - ConstructorDecl* defaultCtor = nullptr; - auto declRefType = as(varDecl->type.type); - if (declRefType) - { - if (auto structDecl = as(declRefType->getDeclRef().getDecl())) - { - defaultCtor = _getDefaultCtor(structDecl); - } - } - - if (defaultCtor) - { - auto* invoke = visitor->getASTBuilder()->create(); - auto member = visitor->getASTBuilder()->getMemberDeclRef(declRefType->getDeclRef(), defaultCtor); - invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->getName(), defaultCtor->loc, nullptr); - return invoke; - } - else - { - auto* defaultCall = visitor->getASTBuilder()->create(); - defaultCall->type = QualType(varDecl->type); - return defaultCall; - } - } - void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl) { DiagnoseIsAllowedInitExpr(varDecl, getSink()); diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index 60e820bbae..350645654b 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -71,22 +71,6 @@ namespace Slang return ctorList; } - bool DiagnoseIsAllowedInitExpr(VarDeclBase* varDecl, DiagnosticSink* sink) - { - if (!varDecl) - return true; - - // find groupshared modifier - if (varDecl->findModifier()) - { - if (sink && varDecl->initExpr) - sink->diagnose(varDecl, Diagnostics::cannotHaveInitializer, varDecl, "groupshared"); - return false; - } - - return true; - } - bool isDefaultInitializable(Type* varDeclType, VarDeclBase* associatedDecl) { if (!DiagnoseIsAllowedInitExpr(associatedDecl, nullptr)) @@ -146,7 +130,7 @@ namespace Slang { auto* invoke = visitor->getASTBuilder()->create(); auto member = visitor->getASTBuilder()->getMemberDeclRef(declRefType->getDeclRef(), defaultCtor); - invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->loc, nullptr); + invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->getName(), defaultCtor->loc, nullptr); invoke->type = varDeclType.type; return invoke; } @@ -171,7 +155,7 @@ namespace Slang { auto* invoke = visitor->getASTBuilder()->create(); auto member = visitor->getASTBuilder()->getMemberDeclRef(structDecl->getDefaultDeclRef(), defaultCtor); - invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->loc, nullptr); + invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultCtor->getName(), defaultCtor->loc, nullptr); invoke->type = structDeclType; return invoke; } @@ -222,7 +206,7 @@ namespace Slang else member = visitor->getASTBuilder()->getMemberDeclRef(structDecl, zeroInitListFunc); - invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, zeroInitListFunc->loc, nullptr); + invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, zeroInitListFunc->getName(), zeroInitListFunc->loc, nullptr); invoke->type = structDeclType; return invoke; } From a73795b43c6aa09e9ef17ee49b142da845dc9f3c Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:41:02 -0400 Subject: [PATCH 073/100] fix up wittness table fufillment: Currently if we have a wrapped type we skip wittness table fufillment checks and try to synth an item incorrectly every-time. This is done to avoid `lookupMember()` checking inheritanceDecl's. Since 2 levels of inheritance is not very common this caused no issues thus far. The changes of this PR is to just lookup using `LookupOptions::IgnoreInheritance` --- source/slang/slang-check-decl.cpp | 30 ++++++++++------------ source/slang/slang-constructor-utility.cpp | 2 +- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 61ffcbc9bc..3231c57700 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -5806,25 +5806,21 @@ namespace Slang // requests will be handled further down. For now we include // lookup results that might be usable, but not as-is. // - LookupResult lookupResult; - if (!isWrapperTypeDecl(context->parentDecl)) - { - lookupResult = lookUpMember(m_astBuilder, this, name, subType, nullptr, LookupMask::Default, LookupOptions::IgnoreBaseInterfaces); + LookupResult lookupResult = lookUpMember(m_astBuilder, this, name, subType, nullptr, LookupMask::Default, LookupOptions((uint8_t)LookupOptions::IgnoreBaseInterfaces | (uint8_t)LookupOptions::IgnoreInheritance)); - if (!lookupResult.isValid()) + if (!lookupResult.isValid()) + { + // If we failed to look up a member with the name of the + // requirement, it may be possible that we can still synthesis the + // implementation if this is one of the known builtin requirements. + // Otherwise, report diagnostic now. + if (!requiredMemberDeclRef.getDecl()->hasModifier() && + !(requiredMemberDeclRef.as() && + getInner(requiredMemberDeclRef.as())->hasModifier())) { - // If we failed to look up a member with the name of the - // requirement, it may be possible that we can still synthesis the - // implementation if this is one of the known builtin requirements. - // Otherwise, report diagnostic now. - if (!requiredMemberDeclRef.getDecl()->hasModifier() && - !(requiredMemberDeclRef.as() && - getInner(requiredMemberDeclRef.as())->hasModifier())) - { - getSink()->diagnose(inheritanceDecl, Diagnostics::typeDoesntImplementInterfaceRequirement, subType, requiredMemberDeclRef); - getSink()->diagnose(requiredMemberDeclRef, Diagnostics::seeDeclarationOf, requiredMemberDeclRef); - return false; - } + getSink()->diagnose(inheritanceDecl, Diagnostics::typeDoesntImplementInterfaceRequirement, subType, requiredMemberDeclRef); + getSink()->diagnose(requiredMemberDeclRef, Diagnostics::seeDeclarationOf, requiredMemberDeclRef); + return false; } } diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index 350645654b..76bdfcc9ae 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -40,7 +40,7 @@ namespace Slang DeclRefType::create(m_astBuilder, structDecl), structDecl->ownedScope, LookupMask::Function, - (LookupOptions)((Index)LookupOptions::IgnoreInheritance | (Index)LookupOptions::IgnoreBaseInterfaces | (Index)LookupOptions::NoDeref)); + (LookupOptions)((uint8_t)LookupOptions::IgnoreInheritance | (uint8_t)LookupOptions::IgnoreBaseInterfaces | (uint8_t)LookupOptions::NoDeref)); if (!ctorLookupResult.isValid()) return ctorList; From afa881217257da070b1dc6b01ea69a04667ceb19 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:16:02 -0400 Subject: [PATCH 074/100] fix `_structHasMemberWithValue` logic --- source/slang/slang-check-decl.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 3231c57700..5f9cb900a6 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2577,8 +2577,14 @@ namespace Slang bool _structHasMemberWithValue(ASTBuilder* m_astBuilder, StructDecl* structDecl) { - return getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance).getFirstOrNull() - || getMembersOfType(m_astBuilder, structDecl).getFirstOrNull(); + if (getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance).getFirstOrNull()) + return true; + + for (auto i : getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance)) + { + if (auto memberStruct = as(i.getDecl()->base.type)) + _structHasMemberWithValue(m_astBuilder, memberStruct); + } } // Concretize interface conformances so that we have witnesses as required for lookup. From f56d34a46f6eda70b20f0f8f3e2aab34ad9af716 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:21:23 -0400 Subject: [PATCH 075/100] fix bug in `_structHasMemberWithValue` --- source/slang/slang-check-decl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 5f9cb900a6..7a5c83929e 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2583,8 +2583,10 @@ namespace Slang for (auto i : getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance)) { if (auto memberStruct = as(i.getDecl()->base.type)) - _structHasMemberWithValue(m_astBuilder, memberStruct); + if (_structHasMemberWithValue(m_astBuilder, memberStruct)) + return true; } + return false; } // Concretize interface conformances so that we have witnesses as required for lookup. From 7df745dfccd5a4c89c63343147199d5bbf937ac1 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:41:05 -0400 Subject: [PATCH 076/100] allow wittness through inheritance (I misread the code comments) --- source/slang/slang-check-decl.cpp | 2 +- tests/compute/assoctype-lookup.slang | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 7a5c83929e..ddca838e9d 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -5814,7 +5814,7 @@ namespace Slang // requests will be handled further down. For now we include // lookup results that might be usable, but not as-is. // - LookupResult lookupResult = lookUpMember(m_astBuilder, this, name, subType, nullptr, LookupMask::Default, LookupOptions((uint8_t)LookupOptions::IgnoreBaseInterfaces | (uint8_t)LookupOptions::IgnoreInheritance)); + LookupResult lookupResult = lookUpMember(m_astBuilder, this, name, subType, nullptr, LookupMask::Default, LookupOptions((uint8_t)LookupOptions::IgnoreBaseInterfaces)); if (!lookupResult.isValid()) { diff --git a/tests/compute/assoctype-lookup.slang b/tests/compute/assoctype-lookup.slang index 348391e217..edfdfedfb8 100644 --- a/tests/compute/assoctype-lookup.slang +++ b/tests/compute/assoctype-lookup.slang @@ -16,8 +16,8 @@ struct StandardBoneWeightSet : IBoneWeightSet { struct PackedType { - uint boneIds : BONEIDS; - uint boneWeights : BONEWEIGHTS; + uint boneIds : BONEIDS = {}; + uint boneWeights : BONEWEIGHTS = {}; }; PackedType field; }; From 2177db4e0ee01c62baf98317af84fb9feefc9bab Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:07:28 -0400 Subject: [PATCH 077/100] try to fix more interface (and such) issues with reordering declarations & bodies of automatic-ctor-generation --- source/slang/slang-check-decl.cpp | 337 +++++++++--------- source/slang/slang-check-overload.cpp | 53 +-- tests/autodiff/bsdf/bsdf-auto-rev.slang | 8 +- tests/compute/dynamic-dispatch-15.slang | 10 +- tests/compute/dynamic-dispatch-7.slang | 2 +- .../mesh/nested-component-write.slang | 4 +- 6 files changed, 210 insertions(+), 204 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index ddca838e9d..0f4b77cd64 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2609,203 +2609,198 @@ namespace Slang { if (auto structDecl = as(aggTypeDecl)) { - // Only generate declarations if we have something that should be taken into account (Inheritance/VarDecl) + // First part of auto-generating constructors/functions is inside `SemanticsDeclConformancesVisitor::visitAggTypeDecl` + // * Create declarations for constructors/functions. + // Second part of auto-generating constructors/functions is inside `SemanticsDeclBodyVisitor::visitAggTypeDecl` + // * Add bodies to our declarations + // + // These are split up so we can assign declarations before we finish definitions + // + // + // Steps: + // 1. Add an declaration for default-ctor if missing a real default-ctor. + // 2. Generate $ZeroInit + // 3. Generate 'member-wise' constructors + + // 1. Add an declaration for default-ctor if missing a real default-ctor. + ConstructorDecl* defaultCtor = nullptr; + List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); + if (!defaultCtor) + { + defaultCtor = _createCtor(this, m_astBuilder, structDecl, {}, getDeclVisibility(structDecl)); + ctorList.add(defaultCtor); + } + + // 2. Generate $ZeroInit if (_structHasMemberWithValue(getASTBuilder(), structDecl)) { - // First part of auto-generating constructors/functions is inside `SemanticsDeclConformancesVisitor::visitAggTypeDecl` - // * Create declarations for constructors/functions. - // Second part of auto-generating constructors/functions is inside `SemanticsDeclBodyVisitor::visitAggTypeDecl` - // * Add bodies to our declarations - // - // These are split up so we can assign declarations before we finish definitions - // - // - // Steps: - // 1. Add an declaration for default-ctor if missing a real default-ctor. - // 2. Generate $ZeroInit - // 3. Generate 'member-wise' constructors - - // 1. Add an declaration for default-ctor if missing a real default-ctor. - ConstructorDecl* defaultCtor = nullptr; - List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); - if (!defaultCtor) + // $ZeroInit is a synthisized static-function only used In 2 cases: + // 1. if `{}` is used inside a `__init()` + // 2. if `{}` is used and a user has a 'synthisized __init()` + // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. + auto zeroInitFunc = m_astBuilder->create(); + auto ctorName = getName("$ZeroInit"); + zeroInitFunc->ownedScope = m_astBuilder->create(); + zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; + zeroInitFunc->ownedScope->parent = getScope(structDecl); + zeroInitFunc->parentDecl = structDecl; + zeroInitFunc->loc = structDecl->loc; + zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; + zeroInitFunc->nameAndLoc.name = ctorName; + zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; + zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); + auto body = m_astBuilder->create(); + body->scopeDecl = m_astBuilder->create(); + body->scopeDecl->ownedScope = m_astBuilder->create(); + body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); + body->scopeDecl->parentDecl = zeroInitFunc; + body->scopeDecl->loc = zeroInitFunc->loc; + body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; + body->closingSourceLoc = zeroInitFunc->closingSourceLoc; + zeroInitFunc->body = body; + body->body = m_astBuilder->create(); + + addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); + addModifier(zeroInitFunc, m_astBuilder->create()); + + addModifier(zeroInitFunc, m_astBuilder->create()); + addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); + addModifier(zeroInitFunc, m_astBuilder->create()); + structDecl->addMember(zeroInitFunc); + } + + // 3. Generate 'member-wise' constructors + // + // Add an empty constructor for all combinations of visibility and access + // which is possible: + // public constructor - usable *outside class scope* in a *different module* + List publicCtorArgs; + // public-internal constructor - usable *outside class scope* in the *same module* + List publicInternalCtorArgs; + // public-private-internal constructor - usable *inside class scope* in the *same module* + List publicInternalPrivateCtorArgs; + + // Harvest parameters which map to the base type ctor. + // Note: assumes 1 structDecl, N number inheritance decl + for (auto inheritanceMember : structDecl->getMembersOfType()) + { + auto declRefType = as(inheritanceMember->base.type); + if (!declRefType) + continue; + auto baseStruct = as(declRefType->getDeclRef().getDecl()); + if (!baseStruct) + continue; + + DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; + + ConstructorDecl* ctorForPublic = nullptr; + ConstructorDecl* ctorForInternal = nullptr; + + // From our synthisized ctor's find the publicMemberCtor and internalMemberCtor. + List baseCtorList = _getCtorList(this->getASTBuilder(), this, baseStruct, nullptr); + for (auto i : baseCtorList) { - defaultCtor = _createCtor(this, m_astBuilder, structDecl, {}, getDeclVisibility(structDecl)); - ctorList.add(defaultCtor); + if (i->containsOption(ConstructorTags::MemberwiseCtorForPublicVisibility)) + ctorForPublic = i; + if (i->containsOption(ConstructorTags::MemberwiseCtorForInternalVisibility)) + ctorForInternal = i; } - // 2. Generate $ZeroInit - if (_structHasMemberWithValue(getASTBuilder(), structDecl)) + // If base is not defined in the same module (or if the internal ctor is missing) + // set the parameter list to a base-type member-wise ctor. + if (baseVisibilityToDerived == DeclVisibility::Public + || !ctorForInternal) { - // $ZeroInit is a synthisized static-function only used In 2 cases: - // 1. if `{}` is used inside a `__init()` - // 2. if `{}` is used and a user has a 'synthisized __init()` - // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. - auto zeroInitFunc = m_astBuilder->create(); - auto ctorName = getName("$ZeroInit"); - zeroInitFunc->ownedScope = m_astBuilder->create(); - zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; - zeroInitFunc->ownedScope->parent = getScope(structDecl); - zeroInitFunc->parentDecl = structDecl; - zeroInitFunc->loc = structDecl->loc; - zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; - zeroInitFunc->nameAndLoc.name = ctorName; - zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; - zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); - auto body = m_astBuilder->create(); - body->scopeDecl = m_astBuilder->create(); - body->scopeDecl->ownedScope = m_astBuilder->create(); - body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); - body->scopeDecl->parentDecl = zeroInitFunc; - body->scopeDecl->loc = zeroInitFunc->loc; - body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; - body->closingSourceLoc = zeroInitFunc->closingSourceLoc; - zeroInitFunc->body = body; - body->body = m_astBuilder->create(); - - addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); - addModifier(zeroInitFunc, m_astBuilder->create()); - - addModifier(zeroInitFunc, m_astBuilder->create()); - addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); - addModifier(zeroInitFunc, m_astBuilder->create()); - structDecl->addMember(zeroInitFunc); + ctorForInternal = ctorForPublic; } - - // 3. Generate 'member-wise' constructors - // - // Add an empty constructor for all combinations of visibility and access - // which is possible: - // public constructor - usable *outside class scope* in a *different module* - List publicCtorArgs; - // public-internal constructor - usable *outside class scope* in the *same module* - List publicInternalCtorArgs; - // public-private-internal constructor - usable *inside class scope* in the *same module* - List publicInternalPrivateCtorArgs; - - // Harvest parameters which map to the base type ctor. - // Note: assumes 1 structDecl, N number inheritance decl - for (auto inheritanceMember : structDecl->getMembersOfType()) + if (ctorForPublic) { - auto declRefType = as(inheritanceMember->base.type); - if (!declRefType) - continue; - auto baseStruct = as(declRefType->getDeclRef().getDecl()); - if (!baseStruct) - continue; - - DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; - - ConstructorDecl* ctorForPublic = nullptr; - ConstructorDecl* ctorForInternal = nullptr; - - // From our synthisized ctor's find the publicMemberCtor and internalMemberCtor. - List baseCtorList = _getCtorList(this->getASTBuilder(), this, baseStruct, nullptr); - for (auto i : baseCtorList) + for (auto i : ctorForPublic->getParameters()) { - if (i->containsOption(ConstructorTags::MemberwiseCtorForPublicVisibility)) - ctorForPublic = i; - if (i->containsOption(ConstructorTags::MemberwiseCtorForInternalVisibility)) - ctorForInternal = i; + publicCtorArgs.add({ i,nullptr }); } - - // If base is not defined in the same module (or if the internal ctor is missing) - // set the parameter list to a base-type member-wise ctor. - if (baseVisibilityToDerived == DeclVisibility::Public - || !ctorForInternal) + for (auto i : ctorForInternal->getParameters()) { - ctorForInternal = ctorForPublic; - } - - if (ctorForPublic) - { - for (auto i : ctorForPublic->getParameters()) - { - publicCtorArgs.add({ i,nullptr }); - } - for (auto i : ctorForInternal->getParameters()) - { - publicInternalCtorArgs.add({ i,nullptr }); - publicInternalPrivateCtorArgs.add({ i,nullptr }); - } + publicInternalCtorArgs.add({ i,nullptr }); + publicInternalPrivateCtorArgs.add({ i,nullptr }); } } + } - // If we have an internal field which lacks an initExpr we cannot allow - // a memberwise ctor to be synthesized for public members. - // This principal also applies for private members and internal/public member-wise ctor synthisis. - DeclVisibility maxVisibilityCtorToGenerate = getDeclVisibility(structDecl); + // If we have an internal field which lacks an initExpr we cannot allow + // a memberwise ctor to be synthesized for public members. + // This principal also applies for private members and internal/public member-wise ctor synthisis. + DeclVisibility maxVisibilityCtorToGenerate = getDeclVisibility(structDecl); - // Here we collect all variables which will be apart of our member-wise ctor's. - for (auto varDeclRef : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) - { - auto varDecl = varDeclRef.getDecl(); - ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); + // Here we collect all variables which will be apart of our member-wise ctor's. + for (auto varDeclRef : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) + { + auto varDecl = varDeclRef.getDecl(); + ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); - // Do not map a read-only variable for default-init - if (!getTypeForDeclRef(m_astBuilder, varDeclRef, varDeclRef.getLoc()).isLeftValue) - continue; + // Do not map a read-only variable for default-init + if (!getTypeForDeclRef(m_astBuilder, varDeclRef, varDeclRef.getLoc()).isLeftValue) + continue; - auto declVisibility = getDeclVisibility(varDecl); - switch (declVisibility) - { - case DeclVisibility::Private: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - if (!varDecl->initExpr) - maxVisibilityCtorToGenerate = DeclVisibility::Private; - break; - case DeclVisibility::Internal: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - publicInternalCtorArgs.add({ varDecl, nullptr }); - if (!varDecl->initExpr) - maxVisibilityCtorToGenerate = DeclVisibility::Internal; - break; - case DeclVisibility::Public: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - publicInternalCtorArgs.add({ varDecl, nullptr }); - publicCtorArgs.add({ varDecl, nullptr }); - break; - default: - // Unknown visibility - SLANG_ASSERT(false); - break; - } + auto declVisibility = getDeclVisibility(varDecl); + switch (declVisibility) + { + case DeclVisibility::Private: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + if (!varDecl->initExpr) + maxVisibilityCtorToGenerate = DeclVisibility::Private; + break; + case DeclVisibility::Internal: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + publicInternalCtorArgs.add({ varDecl, nullptr }); + if (!varDecl->initExpr) + maxVisibilityCtorToGenerate = DeclVisibility::Internal; + break; + case DeclVisibility::Public: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + publicInternalCtorArgs.add({ varDecl, nullptr }); + publicCtorArgs.add({ varDecl, nullptr }); + break; + default: + // Unknown visibility + SLANG_ASSERT(false); + break; } + } - List generatedMemberwiseCtors; - if (maxVisibilityCtorToGenerate >= DeclVisibility::Public) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public)) - generatedMemberwiseCtors.add(generatedCtor); - if (maxVisibilityCtorToGenerate >= DeclVisibility::Internal) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal)) - generatedMemberwiseCtors.add(generatedCtor); - if (maxVisibilityCtorToGenerate >= DeclVisibility::Private) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalPrivateCtorArgs), ctorList, structDecl, DeclVisibility::Private)) - generatedMemberwiseCtors.add(generatedCtor); - - // `checkIfCStyleStruct` must check after we add all possible Ctors. - // If we are a CStyleStruct add DefaultConstructExpr to all params (excluding arg 0) - bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); - if (isCStyleStruct && generatedMemberwiseCtors.getCount() > 0) + List generatedMemberwiseCtors; + if (maxVisibilityCtorToGenerate >= DeclVisibility::Public) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public)) + generatedMemberwiseCtors.add(generatedCtor); + if (maxVisibilityCtorToGenerate >= DeclVisibility::Internal) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal)) + generatedMemberwiseCtors.add(generatedCtor); + if (maxVisibilityCtorToGenerate >= DeclVisibility::Private) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalPrivateCtorArgs), ctorList, structDecl, DeclVisibility::Private)) + generatedMemberwiseCtors.add(generatedCtor); + + // `checkIfCStyleStruct` must check after we add all possible Ctors. + // If we are a CStyleStruct add DefaultConstructExpr to all params (excluding arg 0) + bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); + if (isCStyleStruct && generatedMemberwiseCtors.getCount() > 0) + { + // We know the user provided 0 non-default ctor's, we only had a chance to generate non default Ctors above in this AST pass. + SLANG_ASSERT(generatedMemberwiseCtors.getCount() == 1); + for (auto generatedCtor : generatedMemberwiseCtors) { - // We know the user provided 0 non-default ctor's, we only had a chance to generate non default Ctors above in this AST pass. - SLANG_ASSERT(generatedMemberwiseCtors.getCount() == 1); - for (auto generatedCtor : generatedMemberwiseCtors) + Index paramIndex = 0; + for (ParamDecl* i : generatedCtor->getParameters()) { - Index paramIndex = 0; - for (ParamDecl* i : generatedCtor->getParameters()) + // Never annotate the first parameter to prevent conflict with "DefaultCtor" + if (paramIndex == 0) { - // Never annotate the first parameter to prevent conflict with "DefaultCtor" - if (paramIndex == 0) - { - paramIndex++; - continue; - } paramIndex++; - i->initExpr = createDefaultConstructExprForType(this->getASTBuilder(), (QualType)i->type, i->loc); + continue; } + paramIndex++; + i->initExpr = createDefaultConstructExprForType(this->getASTBuilder(), (QualType)i->type, i->loc); } } } diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index dc0b2a2fe8..2c4e538082 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -2241,6 +2241,33 @@ namespace Slang return argsListBuilder.produceString(); } + + /// We allow a special case for when `funcExpr` is expected to be a Default initializer + /// but none exist. Note, we cannot just create a default initializer for every variable + /// since then we are introducing initialization to every variable through an indirect + /// init returning data. Instead we will call `$ZeroInit` through this logic below. + Expr* _tryToSpecialCaseOverloadDefaultConstructWithoutInit(SemanticsVisitor* visitor, SemanticsVisitor::OverloadResolveContext& context, Expr* expr, OverloadCandidate* bestCandidate) + { + if (context.argCount == 0) + { + auto oldMode = context.mode; + context.mode = SemanticsVisitor::OverloadResolveContext::Mode::JustTrying; + bool arityIsValid = visitor->TryCheckOverloadCandidateArity(context, *bestCandidate); + context.mode = oldMode; + + if (!arityIsValid) + { + auto initListExpr = visitor->getASTBuilder()->create(); + initListExpr->loc = expr->loc; + initListExpr->type = visitor->getASTBuilder()->getInitializerListType(); + Expr* outExpr = nullptr; + if (visitor->_coerceInitializerList(bestCandidate->resultType, &outExpr, initListExpr)) + return outExpr; + } + } + return nullptr; + } + Expr* SemanticsVisitor::ResolveInvoke(InvokeExpr * expr) { OverloadResolveContext context; @@ -2364,6 +2391,9 @@ namespace Slang if (context.bestCandidates[0].status != OverloadCandidate::Status::Applicable) { + if (auto specialCase = _tryToSpecialCaseOverloadDefaultConstructWithoutInit(this, context, expr, &context.bestCandidates[0])) + return specialCase; + // There were multiple equally-good candidates, but none actually usable. // We will construct a diagnostic message to help out. @@ -2419,27 +2449,8 @@ namespace Slang } else if (context.bestCandidate) { - // We allow a special case for when `funcExpr` is expected to be a Default initializer - // but none exist. Note, we cannot just create a default initializer for every variable - // since then we are introducing initialization to every variable through an indirect - // init returning data. Instead we will call `$ZeroInit` through this logic below. - if (context.argCount == 0) - { - auto oldMode = context.mode; - context.mode = OverloadResolveContext::Mode::JustTrying; - bool arityIsValid = TryCheckOverloadCandidateArity(context, *context.bestCandidate); - context.mode = oldMode; - - if (!arityIsValid) - { - auto initListExpr = m_astBuilder->create(); - initListExpr->loc = expr->loc; - initListExpr->type = m_astBuilder->getInitializerListType(); - Expr* outExpr = nullptr; - if (_coerceInitializerList(context.bestCandidate->resultType, &outExpr, initListExpr)) - return outExpr; - } - } + if (auto specialCase = _tryToSpecialCaseOverloadDefaultConstructWithoutInit(this, context, expr, context.bestCandidate)) + return specialCase; // There was one best candidate, even if it might not have been // applicable in the end. diff --git a/tests/autodiff/bsdf/bsdf-auto-rev.slang b/tests/autodiff/bsdf/bsdf-auto-rev.slang index 1bb1989bfb..5e4242ee3c 100644 --- a/tests/autodiff/bsdf/bsdf-auto-rev.slang +++ b/tests/autodiff/bsdf/bsdf-auto-rev.slang @@ -3,10 +3,10 @@ implementing "bsdf-sample"; struct ShadingData { - float3 V; - float3 N; - float3 T; - float3 B; + float3 V = {}; + float3 N = {}; + float3 T = {}; + float3 B = {}; float3 fromLocal(float3 v) { diff --git a/tests/compute/dynamic-dispatch-15.slang b/tests/compute/dynamic-dispatch-15.slang index 2ab169281c..6be4e6505e 100644 --- a/tests/compute/dynamic-dispatch-15.slang +++ b/tests/compute/dynamic-dispatch-15.slang @@ -18,7 +18,7 @@ RWStructuredBuffer gOutputBuffer; RWStructuredBuffer gObj; [numthreads(1, 1, 1)] -void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) { // Test unpacking. float result = 0.0; @@ -48,7 +48,7 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) // Type must be marked `public` to ensure it is visible in the generated DLL. export struct FloatVal : IInterface { - float val; + float val = {}; float run() { return val; @@ -58,7 +58,7 @@ interface ISomething{void g();} struct Float4Struct : ISomething { float4 val; void g() {} } export struct Float4Val : IInterface { - Float4Struct val; + Float4Struct val = {}; float run() { return val.val.x; @@ -66,7 +66,7 @@ export struct Float4Val : IInterface }; export struct IntVal : IInterface { - int val; + int val = {}; float run() { return val; @@ -74,7 +74,7 @@ export struct IntVal : IInterface }; export struct Int4Val : IInterface { - int4 val; + int4 val = {}; float run() { return val.x; diff --git a/tests/compute/dynamic-dispatch-7.slang b/tests/compute/dynamic-dispatch-7.slang index 7f516b0d55..c8dada852a 100644 --- a/tests/compute/dynamic-dispatch-7.slang +++ b/tests/compute/dynamic-dispatch-7.slang @@ -45,7 +45,7 @@ struct Impl : IInterface { struct TAssoc : IAssoc { - int base; + int base = {}; int Compute() { return base; diff --git a/tests/pipeline/rasterization/mesh/nested-component-write.slang b/tests/pipeline/rasterization/mesh/nested-component-write.slang index 681331a51a..273eae1037 100644 --- a/tests/pipeline/rasterization/mesh/nested-component-write.slang +++ b/tests/pipeline/rasterization/mesh/nested-component-write.slang @@ -7,7 +7,7 @@ struct Foo { - float4 pos : SV_Position; + float4 pos : SV_Position = {}; Bar bar; }; @@ -18,7 +18,7 @@ struct Bar struct Baz { - float3 color; + float3 color = {}; }; struct Vertex From 989837f7f02f51cc9f7ce46d04f321caefc6ddc1 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:54:58 -0400 Subject: [PATCH 078/100] try another balance of fixes --- source/slang/slang-check-decl.cpp | 247 +++++++++++++++--------------- 1 file changed, 125 insertions(+), 122 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 0f4b77cd64..8c5d8e9b4c 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2618,20 +2618,11 @@ namespace Slang // // // Steps: - // 1. Add an declaration for default-ctor if missing a real default-ctor. - // 2. Generate $ZeroInit + // 1. Generate $ZeroInit + // 2. Add an declaration for default-ctor if missing a real default-ctor. // 3. Generate 'member-wise' constructors - // 1. Add an declaration for default-ctor if missing a real default-ctor. - ConstructorDecl* defaultCtor = nullptr; - List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); - if (!defaultCtor) - { - defaultCtor = _createCtor(this, m_astBuilder, structDecl, {}, getDeclVisibility(structDecl)); - ctorList.add(defaultCtor); - } - - // 2. Generate $ZeroInit + // 1. Generate $ZeroInit if (_structHasMemberWithValue(getASTBuilder(), structDecl)) { // $ZeroInit is a synthisized static-function only used In 2 cases: @@ -2669,138 +2660,150 @@ namespace Slang structDecl->addMember(zeroInitFunc); } - // 3. Generate 'member-wise' constructors - // - // Add an empty constructor for all combinations of visibility and access - // which is possible: - // public constructor - usable *outside class scope* in a *different module* - List publicCtorArgs; - // public-internal constructor - usable *outside class scope* in the *same module* - List publicInternalCtorArgs; - // public-private-internal constructor - usable *inside class scope* in the *same module* - List publicInternalPrivateCtorArgs; - - // Harvest parameters which map to the base type ctor. - // Note: assumes 1 structDecl, N number inheritance decl - for (auto inheritanceMember : structDecl->getMembersOfType()) + if (_structHasMemberWithValue(getASTBuilder(), structDecl)) { - auto declRefType = as(inheritanceMember->base.type); - if (!declRefType) - continue; - auto baseStruct = as(declRefType->getDeclRef().getDecl()); - if (!baseStruct) - continue; - - DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; - - ConstructorDecl* ctorForPublic = nullptr; - ConstructorDecl* ctorForInternal = nullptr; - - // From our synthisized ctor's find the publicMemberCtor and internalMemberCtor. - List baseCtorList = _getCtorList(this->getASTBuilder(), this, baseStruct, nullptr); - for (auto i : baseCtorList) + // 2. Add an declaration for default-ctor if missing a real default-ctor. + ConstructorDecl* defaultCtor = nullptr; + List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); + if (!defaultCtor) { - if (i->containsOption(ConstructorTags::MemberwiseCtorForPublicVisibility)) - ctorForPublic = i; - if (i->containsOption(ConstructorTags::MemberwiseCtorForInternalVisibility)) - ctorForInternal = i; + defaultCtor = _createCtor(this, m_astBuilder, structDecl, {}, getDeclVisibility(structDecl)); + ctorList.add(defaultCtor); } - // If base is not defined in the same module (or if the internal ctor is missing) - // set the parameter list to a base-type member-wise ctor. - if (baseVisibilityToDerived == DeclVisibility::Public - || !ctorForInternal) - { - ctorForInternal = ctorForPublic; - } - if (ctorForPublic) + // 3. Generate 'member-wise' constructors + // + // Add an empty constructor for all combinations of visibility and access + // which is possible: + // public constructor - usable *outside class scope* in a *different module* + List publicCtorArgs; + // public-internal constructor - usable *outside class scope* in the *same module* + List publicInternalCtorArgs; + // public-private-internal constructor - usable *inside class scope* in the *same module* + List publicInternalPrivateCtorArgs; + + // Harvest parameters which map to the base type ctor. + // Note: assumes 1 structDecl, N number inheritance decl + for (auto inheritanceMember : structDecl->getMembersOfType()) { - for (auto i : ctorForPublic->getParameters()) + auto declRefType = as(inheritanceMember->base.type); + if (!declRefType) + continue; + auto baseStruct = as(declRefType->getDeclRef().getDecl()); + if (!baseStruct) + continue; + + DeclVisibility baseVisibilityToDerived = (isVisibilityOfDeclVisibleInScope(baseStruct, DeclVisibility::Internal, structDecl->ownedScope)) ? DeclVisibility::Internal : DeclVisibility::Public; + + ConstructorDecl* ctorForPublic = nullptr; + ConstructorDecl* ctorForInternal = nullptr; + + // From our synthisized ctor's find the publicMemberCtor and internalMemberCtor. + List baseCtorList = _getCtorList(this->getASTBuilder(), this, baseStruct, nullptr); + for (auto i : baseCtorList) { - publicCtorArgs.add({ i,nullptr }); + if (i->containsOption(ConstructorTags::MemberwiseCtorForPublicVisibility)) + ctorForPublic = i; + if (i->containsOption(ConstructorTags::MemberwiseCtorForInternalVisibility)) + ctorForInternal = i; } - for (auto i : ctorForInternal->getParameters()) + + // If base is not defined in the same module (or if the internal ctor is missing) + // set the parameter list to a base-type member-wise ctor. + if (baseVisibilityToDerived == DeclVisibility::Public + || !ctorForInternal) { - publicInternalCtorArgs.add({ i,nullptr }); - publicInternalPrivateCtorArgs.add({ i,nullptr }); + ctorForInternal = ctorForPublic; } - } - } + if (ctorForPublic) + { + for (auto i : ctorForPublic->getParameters()) + { + publicCtorArgs.add({ i,nullptr }); + } + for (auto i : ctorForInternal->getParameters()) + { + publicInternalCtorArgs.add({ i,nullptr }); + publicInternalPrivateCtorArgs.add({ i,nullptr }); + } + } + } - // If we have an internal field which lacks an initExpr we cannot allow - // a memberwise ctor to be synthesized for public members. - // This principal also applies for private members and internal/public member-wise ctor synthisis. - DeclVisibility maxVisibilityCtorToGenerate = getDeclVisibility(structDecl); + // If we have an internal field which lacks an initExpr we cannot allow + // a memberwise ctor to be synthesized for public members. + // This principal also applies for private members and internal/public member-wise ctor synthisis. + DeclVisibility maxVisibilityCtorToGenerate = getDeclVisibility(structDecl); - // Here we collect all variables which will be apart of our member-wise ctor's. - for (auto varDeclRef : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) - { - auto varDecl = varDeclRef.getDecl(); - ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); + // Here we collect all variables which will be apart of our member-wise ctor's. + for (auto varDeclRef : getMembersOfType(getASTBuilder(), structDecl, MemberFilterStyle::Instance)) + { + auto varDecl = varDeclRef.getDecl(); + ensureDecl(varDecl, DeclCheckState::TypesFullyResolved); - // Do not map a read-only variable for default-init - if (!getTypeForDeclRef(m_astBuilder, varDeclRef, varDeclRef.getLoc()).isLeftValue) - continue; + // Do not map a read-only variable for default-init + if (!getTypeForDeclRef(m_astBuilder, varDeclRef, varDeclRef.getLoc()).isLeftValue) + continue; - auto declVisibility = getDeclVisibility(varDecl); - switch (declVisibility) - { - case DeclVisibility::Private: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - if (!varDecl->initExpr) - maxVisibilityCtorToGenerate = DeclVisibility::Private; - break; - case DeclVisibility::Internal: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - publicInternalCtorArgs.add({ varDecl, nullptr }); - if (!varDecl->initExpr) - maxVisibilityCtorToGenerate = DeclVisibility::Internal; - break; - case DeclVisibility::Public: - publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); - publicInternalCtorArgs.add({ varDecl, nullptr }); - publicCtorArgs.add({ varDecl, nullptr }); - break; - default: - // Unknown visibility - SLANG_ASSERT(false); - break; + auto declVisibility = getDeclVisibility(varDecl); + switch (declVisibility) + { + case DeclVisibility::Private: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + if (!varDecl->initExpr) + maxVisibilityCtorToGenerate = DeclVisibility::Private; + break; + case DeclVisibility::Internal: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + publicInternalCtorArgs.add({ varDecl, nullptr }); + if (!varDecl->initExpr) + maxVisibilityCtorToGenerate = DeclVisibility::Internal; + break; + case DeclVisibility::Public: + publicInternalPrivateCtorArgs.add({ varDecl, nullptr }); + publicInternalCtorArgs.add({ varDecl, nullptr }); + publicCtorArgs.add({ varDecl, nullptr }); + break; + default: + // Unknown visibility + SLANG_ASSERT(false); + break; + } } - } - List generatedMemberwiseCtors; - if (maxVisibilityCtorToGenerate >= DeclVisibility::Public) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public)) - generatedMemberwiseCtors.add(generatedCtor); - if (maxVisibilityCtorToGenerate >= DeclVisibility::Internal) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal)) - generatedMemberwiseCtors.add(generatedCtor); - if (maxVisibilityCtorToGenerate >= DeclVisibility::Private) - if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalPrivateCtorArgs), ctorList, structDecl, DeclVisibility::Private)) - generatedMemberwiseCtors.add(generatedCtor); - - // `checkIfCStyleStruct` must check after we add all possible Ctors. - // If we are a CStyleStruct add DefaultConstructExpr to all params (excluding arg 0) - bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); - if (isCStyleStruct && generatedMemberwiseCtors.getCount() > 0) - { - // We know the user provided 0 non-default ctor's, we only had a chance to generate non default Ctors above in this AST pass. - SLANG_ASSERT(generatedMemberwiseCtors.getCount() == 1); - for (auto generatedCtor : generatedMemberwiseCtors) + List generatedMemberwiseCtors; + if (maxVisibilityCtorToGenerate >= DeclVisibility::Public) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicCtorArgs), ctorList, structDecl, DeclVisibility::Public)) + generatedMemberwiseCtors.add(generatedCtor); + if (maxVisibilityCtorToGenerate >= DeclVisibility::Internal) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalCtorArgs), ctorList, structDecl, DeclVisibility::Internal)) + generatedMemberwiseCtors.add(generatedCtor); + if (maxVisibilityCtorToGenerate >= DeclVisibility::Private) + if (auto generatedCtor = _tryToGenerateCtorWithArgList(this, this->getASTBuilder(), std::move(publicInternalPrivateCtorArgs), ctorList, structDecl, DeclVisibility::Private)) + generatedMemberwiseCtors.add(generatedCtor); + + // `checkIfCStyleStruct` must check after we add all possible Ctors. + // If we are a CStyleStruct add DefaultConstructExpr to all params (excluding arg 0) + bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); + if (isCStyleStruct && generatedMemberwiseCtors.getCount() > 0) { - Index paramIndex = 0; - for (ParamDecl* i : generatedCtor->getParameters()) + // We know the user provided 0 non-default ctor's, we only had a chance to generate non default Ctors above in this AST pass. + SLANG_ASSERT(generatedMemberwiseCtors.getCount() == 1); + for (auto generatedCtor : generatedMemberwiseCtors) { - // Never annotate the first parameter to prevent conflict with "DefaultCtor" - if (paramIndex == 0) + Index paramIndex = 0; + for (ParamDecl* i : generatedCtor->getParameters()) { + // Never annotate the first parameter to prevent conflict with "DefaultCtor" + if (paramIndex == 0) + { + paramIndex++; + continue; + } paramIndex++; - continue; + i->initExpr = createDefaultConstructExprForType(this->getASTBuilder(), (QualType)i->type, i->loc); } - paramIndex++; - i->initExpr = createDefaultConstructExprForType(this->getASTBuilder(), (QualType)i->type, i->loc); } } } From c135f8531212566981ff94d66baee61b6bb23a52 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:23:28 -0400 Subject: [PATCH 079/100] fix bug with checking for possible values in struct --- source/slang/slang-check-decl.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 8c5d8e9b4c..eeb1b2015b 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2575,16 +2575,22 @@ namespace Slang return generatedCtor; } + /// TODO: cache result bool _structHasMemberWithValue(ASTBuilder* m_astBuilder, StructDecl* structDecl) { if (getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance).getFirstOrNull()) return true; - for (auto i : getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance)) + for (auto inheritanceMember : getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance)) { - if (auto memberStruct = as(i.getDecl()->base.type)) - if (_structHasMemberWithValue(m_astBuilder, memberStruct)) - return true; + auto declRefType = as(inheritanceMember.getDecl()->base.type); + if (!declRefType) + continue; + auto baseStruct = as(declRefType->getDeclRef().getDecl()); + if (!baseStruct) + continue; + if (_structHasMemberWithValue(m_astBuilder, baseStruct)) + return true; } return false; } @@ -2610,9 +2616,10 @@ namespace Slang if (auto structDecl = as(aggTypeDecl)) { // First part of auto-generating constructors/functions is inside `SemanticsDeclConformancesVisitor::visitAggTypeDecl` - // * Create declarations for constructors/functions. + // * Create declarations for constructors/functions. This is important so Slang may use the declarations before + // we have the chance to synthisize function bodies // Second part of auto-generating constructors/functions is inside `SemanticsDeclBodyVisitor::visitAggTypeDecl` - // * Add bodies to our declarations + // * Add bodies to our declarations. // // These are split up so we can assign declarations before we finish definitions // @@ -2660,6 +2667,7 @@ namespace Slang structDecl->addMember(zeroInitFunc); } + if (_structHasMemberWithValue(getASTBuilder(), structDecl)) { // 2. Add an declaration for default-ctor if missing a real default-ctor. @@ -8094,9 +8102,10 @@ namespace Slang return; // First part of auto-generating constructors/functions is inside `SemanticsDeclConformancesVisitor::visitAggTypeDecl` - // * Create declarations for constructors/functions. + // * Create declarations for constructors/functions. This is important so Slang may use the declarations before + // we have the chance to synthisize function bodies // Second part of auto-generating constructors/functions is inside `SemanticsDeclBodyVisitor::visitAggTypeDecl` - // * Add bodies to our declarations + // * Add bodies to our declarations. // // These are split up so we can assign declarations before we finish definitions // From 7312af19cfbb340b26e987596cb7639319f13e88 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:32:21 -0400 Subject: [PATCH 080/100] remove one of the backup-overload-resolution-hack-cases that was added + `SemanticsDeclConformancesVisitor::visitAggTypeDecl` cleanup --- source/slang/slang-check-decl.cpp | 70 ++++++++++++++------------- source/slang/slang-check-overload.cpp | 3 -- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index eeb1b2015b..12c8d1b180 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2576,6 +2576,9 @@ namespace Slang } /// TODO: cache result + /// Since we require to generate all declarations for ctor's in the conformance pass + /// Slang needs to be 100% certain that the ctor we are generating is viable, else + /// the wittness tables we will setup with our ctor-declarations will be invalid. bool _structHasMemberWithValue(ASTBuilder* m_astBuilder, StructDecl* structDecl) { if (getMembersOfType(m_astBuilder, structDecl, MemberFilterStyle::Instance).getFirstOrNull()) @@ -2629,47 +2632,46 @@ namespace Slang // 2. Add an declaration for default-ctor if missing a real default-ctor. // 3. Generate 'member-wise' constructors - // 1. Generate $ZeroInit if (_structHasMemberWithValue(getASTBuilder(), structDecl)) { + // 1. Generate $ZeroInit + // // $ZeroInit is a synthisized static-function only used In 2 cases: // 1. if `{}` is used inside a `__init()` // 2. if `{}` is used and a user has a 'synthisized __init()` // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. - auto zeroInitFunc = m_astBuilder->create(); - auto ctorName = getName("$ZeroInit"); - zeroInitFunc->ownedScope = m_astBuilder->create(); - zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; - zeroInitFunc->ownedScope->parent = getScope(structDecl); - zeroInitFunc->parentDecl = structDecl; - zeroInitFunc->loc = structDecl->loc; - zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; - zeroInitFunc->nameAndLoc.name = ctorName; - zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; - zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); - auto body = m_astBuilder->create(); - body->scopeDecl = m_astBuilder->create(); - body->scopeDecl->ownedScope = m_astBuilder->create(); - body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); - body->scopeDecl->parentDecl = zeroInitFunc; - body->scopeDecl->loc = zeroInitFunc->loc; - body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; - body->closingSourceLoc = zeroInitFunc->closingSourceLoc; - zeroInitFunc->body = body; - body->body = m_astBuilder->create(); - - addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); - addModifier(zeroInitFunc, m_astBuilder->create()); - - addModifier(zeroInitFunc, m_astBuilder->create()); - addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); - addModifier(zeroInitFunc, m_astBuilder->create()); - structDecl->addMember(zeroInitFunc); - } - + { + auto zeroInitFunc = m_astBuilder->create(); + auto ctorName = getName("$ZeroInit"); + zeroInitFunc->ownedScope = m_astBuilder->create(); + zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; + zeroInitFunc->ownedScope->parent = getScope(structDecl); + zeroInitFunc->parentDecl = structDecl; + zeroInitFunc->loc = structDecl->loc; + zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; + zeroInitFunc->nameAndLoc.name = ctorName; + zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; + zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); + auto body = m_astBuilder->create(); + body->scopeDecl = m_astBuilder->create(); + body->scopeDecl->ownedScope = m_astBuilder->create(); + body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); + body->scopeDecl->parentDecl = zeroInitFunc; + body->scopeDecl->loc = zeroInitFunc->loc; + body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; + body->closingSourceLoc = zeroInitFunc->closingSourceLoc; + zeroInitFunc->body = body; + body->body = m_astBuilder->create(); + + addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); + addModifier(zeroInitFunc, m_astBuilder->create()); + + addModifier(zeroInitFunc, m_astBuilder->create()); + addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); + addModifier(zeroInitFunc, m_astBuilder->create()); + structDecl->addMember(zeroInitFunc); + } - if (_structHasMemberWithValue(getASTBuilder(), structDecl)) - { // 2. Add an declaration for default-ctor if missing a real default-ctor. ConstructorDecl* defaultCtor = nullptr; List ctorList = _getCtorList(this->getASTBuilder(), this, structDecl, &defaultCtor); diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 2c4e538082..e655eeedc2 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -2391,9 +2391,6 @@ namespace Slang if (context.bestCandidates[0].status != OverloadCandidate::Status::Applicable) { - if (auto specialCase = _tryToSpecialCaseOverloadDefaultConstructWithoutInit(this, context, expr, &context.bestCandidates[0])) - return specialCase; - // There were multiple equally-good candidates, but none actually usable. // We will construct a diagnostic message to help out. From 92ed12a2f2b31649ceadc08d580c4dbab947cc9a Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:16:53 -0400 Subject: [PATCH 081/100] fix incorrect overload candidate resolution fix incorrect overload candidate resolution to allow AssocType to function with StructDecl resolution. --- source/slang/slang-check-overload.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index e655eeedc2..2c1efb067b 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -1401,6 +1401,11 @@ namespace Slang OverloadCandidate* left, OverloadCandidate* right) { + // If candidates are equal (which is possible if we have an overload from `AssocType` and `StructDecl`) + // We need to pick 1 to keep. Overlapping lookups with `__init()` are common with auto-diff. + if (left->item.declRef == right->item.declRef) + return -1; + // If one candidate got further along in validation, pick it if (left->status != right->status) return int(right->status) - int(left->status); From 1164d27c65aa2be6c3ddc496105b9afac727318e Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Thu, 5 Sep 2024 19:53:28 -0400 Subject: [PATCH 082/100] address autodiff failiures 1. fix auto-diff issues that cause incorrect `no_diff` error when Slang should not error 2. change when Slang applies to auto-gen parameters `no_diff` to be more correct/accurate --- source/slang/slang-check-decl.cpp | 12 ++++--- source/slang/slang-check-expr.cpp | 10 ++++-- ...init-list-with-autodiff-attributes-3.slang | 31 +++++++++++++++++++ ...init-list-with-autodiff-attributes-4.slang | 29 +++++++++++++++++ 4 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-3.slang create mode 100644 tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-4.slang diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 927da6301a..5142ab78fd 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -8484,10 +8484,14 @@ namespace Slang member = members[memberIndex++].getDecl(); } - // Check for differentiability of member. checking all 'InheritanceDecl's earlier in 'visitAggTypeDecl' - // propegates DerivativeMemberAtribute to derivative containing attributes. - if (!ctor->hasModifier() && !member->hasModifier()) - addModifier(param, m_astBuilder->create()); + // 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()) + { + auto noDiffMod = m_astBuilder->create(); + noDiffMod->loc = param->loc; + addModifier(param, noDiffMod); + } addCudaHostModifierIfRequired(ctor, member, foundCudaHostModifier); diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 43e61090e1..5c3637b762 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -2792,9 +2792,13 @@ namespace Slang } else { - getSink()->diagnose( - m_treatAsDifferentiableExpr, - Diagnostics::useOfNoDiffOnDifferentiableFunc); + // We should only error if our TreatAsDifferentiableExpr::Flavor is NoDiff. + if (m_treatAsDifferentiableExpr->flavor == TreatAsDifferentiableExpr::Flavor::NoDiff) + { + getSink()->diagnose( + m_treatAsDifferentiableExpr, + Diagnostics::useOfNoDiffOnDifferentiableFunc); + } } } } diff --git a/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-3.slang b/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-3.slang new file mode 100644 index 0000000000..17df592a46 --- /dev/null +++ b/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-3.slang @@ -0,0 +1,31 @@ +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute + +struct Test1 : IDifferentiable +{ + float3 a; +}; +struct TestWrapper +{ + Test1 data1; +} + +//CHECK: computeMain + +[Differentiable] +TestWrapper getWrapper() +{ + return { float3(1) }; +} + +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + TestWrapper test1 = getWrapper(); + outputBuffer[0] = true + && test1.data1.a[0] == 1 + && test1.data1.a[1] == 1 + && test1.data1.a[2] == 1 + ; +} \ No newline at end of file diff --git a/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-4.slang b/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-4.slang new file mode 100644 index 0000000000..9791bbe8ca --- /dev/null +++ b/tests/language-feature/initializer-lists/init-list-with-autodiff-attributes-4.slang @@ -0,0 +1,29 @@ +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute + +struct Test1 : IDifferentiable +{ + float3 a; + no_diff float3 b; +}; + +//CHECK: computeMain + +[Differentiable] +Test1 getWrapper() +{ + return { float3(1), float3(1) }; +} + +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Test1 test1 = getWrapper(); + outputBuffer[0] = true + && test1.a[0] == 1 + && test1.a[1] == 1 + && test1.a[2] == 1 + && test1.b[0] == 1 + ; +} \ No newline at end of file From 37e788e2ec58d7532589086ea85f9b692e204a04 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 6 Sep 2024 09:49:35 -0400 Subject: [PATCH 083/100] fix crash --- source/slang/slang-check-conversion.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index ab56c49388..ff9a6a6648 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -237,7 +237,8 @@ namespace Slang if (!canCoerce(toType, arg->type, nullptr)) { - *outToExpr = arg; + if(outToExpr) + *outToExpr = arg; return true; } From 6587a3fd0622abf5589774214bcc85464490d994 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:11:01 -0400 Subject: [PATCH 084/100] fix vectors to parse correctly with `{...}`, change tests to `dxil` to better report compile failiures with hlsl --- source/slang/slang-check-conversion.cpp | 19 +++++++++++++++++-- .../cstyle-init-list-2.slang | 2 +- .../struct-swizzle-initializer-list.slang | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index ff9a6a6648..074181177d 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -34,6 +34,16 @@ namespace Slang return kBuiltinConversion_Unknown; } + bool isSimpleType(Type* type) + { + if (as(type)) return true; + if (as(type)) return true; + if (as(type)) return true; + if (as(type)) + { + return true; + } + } bool SemanticsVisitor::isEffectivelyScalarForInitializerLists( Type* type) { @@ -92,7 +102,12 @@ namespace Slang if(isEffectivelyScalarForInitializerLists(fromExpr->type)) return false; - // If 2 types are equal, we know the types can be coerced directly + // If 2 types are "broadly equal" we know the types can be coerced directly + // since otherwise trying to solve `float3 tmp[2] = {float3(val), float3(val)};` will break down into searching for `float` + // (which we don't have in our init-list argument list, this will error). + // + // This logic should be completly cleaned up at some point by only using constructors for `{...}` and attempting to use + // constructors before fallback coerce logic is tried. if (toType->equals(fromExpr->type)) return true; @@ -128,7 +143,7 @@ namespace Slang // for aggregate initialization. // auto firstInitExpr = fromInitializerListExpr->args[ioInitArgIndex]; - if(canCoerce(toType, firstInitExpr->type, firstInitExpr) && (shouldUseInitializerDirectly(toType, firstInitExpr))) + if(shouldUseInitializerDirectly(toType, firstInitExpr) && canCoerce(toType, firstInitExpr->type, firstInitExpr)) { ioInitArgIndex++; return _coerce( diff --git a/tests/language-feature/initializer-lists/cstyle-init-list-2.slang b/tests/language-feature/initializer-lists/cstyle-init-list-2.slang index f98c3bb59b..2c840f4667 100644 --- a/tests/language-feature/initializer-lists/cstyle-init-list-2.slang +++ b/tests/language-feature/initializer-lists/cstyle-init-list-2.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute +//TEST:SIMPLE(filecheck=CHECK): -target dxil -entry computeMain -stage compute -profile sm_6_5 //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj //TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF): -vk -shaderobj diff --git a/tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang b/tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang index 6dc9a9f712..15ec428023 100644 --- a/tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang +++ b/tests/language-feature/initializer-lists/struct-swizzle-initializer-list.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute +//TEST:SIMPLE(filecheck=CHECK): -target dxil -entry computeMain -stage compute -profile sm_6_5 //CHECK: computeMain From f5bbca06a6927f3a24b0ad928e1aa99338dfe0f9 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:24:40 -0400 Subject: [PATCH 085/100] remove unused func --- source/slang/slang-check-conversion.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 074181177d..9fb5a3cdc2 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -34,16 +34,6 @@ namespace Slang return kBuiltinConversion_Unknown; } - bool isSimpleType(Type* type) - { - if (as(type)) return true; - if (as(type)) return true; - if (as(type)) return true; - if (as(type)) - { - return true; - } - } bool SemanticsVisitor::isEffectivelyScalarForInitializerLists( Type* type) { From 2b4bb0d7038df2029c8267e21b14a4720059f3b0 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 6 Sep 2024 12:03:28 -0400 Subject: [PATCH 086/100] use more accurate logic to resolve generics wrapped init-list logic --- source/slang/slang-check-conversion.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 9fb5a3cdc2..2f2baaaa07 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -68,6 +68,16 @@ namespace Slang return true; } + // + bool isSameSimpleExprType(Type* type1, Type* type2) + { + if (as(type1) && as(type2)) return true; + if (as(type1) && as(type2)) return true; + if (as(type1) && as(type2)) return true; + if (as(type1) && as(type2)) return true; + return false; + } + bool SemanticsVisitor::shouldUseInitializerDirectly( Type* toType, Expr* fromExpr) @@ -101,6 +111,11 @@ namespace Slang if (toType->equals(fromExpr->type)) return true; + // `vector` and `vector` may not be copyable, but, we have no choice in this senario but to assume coerce logic + // can resolve such situations + if (isSameSimpleExprType(toType, fromExpr->type)) + return true; + return false; } From efbca49bb9c5ec170c72970d3768c6395231fe6e Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:58:27 -0400 Subject: [PATCH 087/100] add old style init list support --> deprecated --- source/slang/slang-check-conversion.cpp | 327 +++++++++++------- source/slang/slang-check-impl.h | 2 + source/slang/slang-diagnostic-defs.h | 3 +- .../deprecated-init-list-behavior.slang | 38 ++ 4 files changed, 244 insertions(+), 126 deletions(-) create mode 100644 tests/language-feature/initializer-lists/deprecated-init-list-behavior.slang diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 2f2baaaa07..3a57ec1f2d 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -119,6 +119,7 @@ namespace Slang return false; } + template bool SemanticsVisitor::_readValueFromInitializerList( Type* toType, Expr** outToExpr, @@ -176,7 +177,7 @@ namespace Slang // The fallback case is to recursively read the // type from the same list as an aggregate. // - return _readAggregateValueFromInitializerList( + return _readAggregateValueFromInitializerList( toType, outToExpr, fromInitializerListExpr, @@ -233,6 +234,7 @@ namespace Slang return nullptr; } + template bool SemanticsVisitor::_readAggregateValueFromInitializerList( Type* inToType, Expr** outToExpr, @@ -307,7 +309,7 @@ namespace Slang for(UInt ee = 0; ee < elementCount; ++ee) { Expr* coercedArg = nullptr; - bool argResult = _readValueFromInitializerList( + bool argResult = _readValueFromInitializerList( toElementType, outToExpr ? &coercedArg : nullptr, fromInitializerListExpr, @@ -355,7 +357,7 @@ namespace Slang for(UInt ee = 0; ee < elementCount; ++ee) { Expr* coercedArg = nullptr; - bool argResult = _readValueFromInitializerList( + bool argResult = _readValueFromInitializerList( toElementType, outToExpr ? &coercedArg : nullptr, fromInitializerListExpr, @@ -381,7 +383,7 @@ namespace Slang while(ioArgIndex < argCount) { Expr* coercedArg = nullptr; - bool argResult = _readValueFromInitializerList( + bool argResult = _readValueFromInitializerList( toElementType, outToExpr ? &coercedArg : nullptr, fromInitializerListExpr, @@ -444,7 +446,7 @@ namespace Slang for(UInt rr = 0; rr < rowCount; ++rr) { Expr* coercedArg = nullptr; - bool argResult = _readValueFromInitializerList( + bool argResult = _readValueFromInitializerList( toRowType, outToExpr ? &coercedArg : nullptr, fromInitializerListExpr, @@ -462,153 +464,210 @@ namespace Slang } else if(auto toDeclRefType = as(toType)) { - auto toTypeDeclRef = toDeclRefType->getDeclRef(); - if(auto toStructDeclRef = toTypeDeclRef.as()) + // We allow using legacy "init list" logic as a backup if something fails + if constexpr (UseLegacyLogic) { - // We will try to coerce the initializer list into a struct following these steps: - // 1. Ensure our `StructDecl` has declaratations created for all auto-generated constructors - // 2. We have a `{}` (0 arguments), try to coerce - // 3. We have a `{arg1, arg2...}`, try to coerce - - auto toStructDecl = toStructDeclRef.getDecl(); - // 1. Ensure our `StructDecl` has declaratations created for all auto-generated constructors - ensureDecl(toStructDecl, DeclCheckState::DefaultConstructorReadyForUse); - - // 2. We have a `{}` (0 arguments), try to coerce - if (argCount == 0) + auto toTypeDeclRef = toDeclRefType->getDeclRef(); + if (auto toStructDeclRef = toTypeDeclRef.as()) { - if (outToExpr) + // Trying to initialize a `struct` type given an initializer list. + // + // Before we iterate over the fields, we want to check if this struct + // inherits from another `struct` type. If so, we want to read + // an initializer for that base type first. + // + if (auto baseStructType = findBaseStructType(m_astBuilder, toStructDeclRef)) { - *outToExpr = constructZeroInitListFunc(this, toStructDecl, toType, ConstructZeroInitListOptions::CheckToAvoidRecursion); - (*outToExpr)->loc = fromInitializerListExpr->loc; - } - return true; - } - - // 3. We have a `{arg1, arg2...}`, try to coerce - // - // For this situation we have more steps: - // a. Find constructor candidate for our particular init-list - // b. Collect and coerce init-list arguments into constructor parameters - // c. Create InvokeExpr for our valid ConstructorDecl - List ctorList = _getCtorList(this->getASTBuilder(), this, toStructDecl, nullptr); - bool allowCStyleInitList = checkIfCStyleStruct(this, toStructDecl); - - List maybeArgList; - maybeArgList.reserve(argCount); - Index ioArgIndexMirror = ioArgIndex; - UInt ioArgIndexCandidate = 0; - - for (auto& ctor : ctorList) - { - // a. Find constructor candidate for our particular init-list - - // Don't try to init default ctor with this logic - auto ctorParamCount = ctor->getParameters().getCount(); - if (ctorParamCount == 0) - continue; + Expr* coercedArg = nullptr; + bool argResult = _readValueFromInitializerList( + baseStructType, + outToExpr ? &coercedArg : nullptr, + fromInitializerListExpr, + ioArgIndex); - ioArgIndexCandidate = ioArgIndexMirror; - ioArgIndex = ctorParamCount; - - // if allowCStyleInitList, process any ctor which comes next using the most members possible. ioArgIndex may not be 0. - // if !allowCStyleInitList, process any ctor that exactly matched our argument count. ioArgIndex must start at 0. - if (!allowCStyleInitList && ctorParamCount != Index(argCount)) - continue; + // No point in trying further if any argument fails + if (!argResult) + return false; - // b. Collect and coerce init-list arguments into constructor parameters - List maybeCandidate; - auto parameters = getParameters(m_astBuilder, ctor); - auto parametersCount = parameters.getCount(); + if (coercedArg) + { + coercedArgs.add(coercedArg); + } + } - for (auto index = coercedArgs.getCount(); index < parametersCount; index++) + // We will go through the fields in order and try to match them + // up with initializer arguments. + // + for (auto fieldDeclRef : getMembersOfType(m_astBuilder, toStructDeclRef, MemberFilterStyle::Instance)) { - // If we ran out of elements and allow using a c-style-partial-initialization-list, end early. - if ((Index)ioArgIndexCandidate > fromInitializerListExpr->args.getCount()) - break; - - auto ctorParam = parameters[index]; - auto paramType = ctorParam.getDecl()->type.type; - for (auto i : getMembersOfType(m_astBuilder, toStructDeclRef, MemberFilterStyle::Instance)) - if (i.getDecl()->type.type == paramType) - paramType = getType(m_astBuilder, i); - Expr* coercedArg = nullptr; - _readValueFromInitializerList( - paramType, - &coercedArg, + bool argResult = _readValueFromInitializerList( + getType(m_astBuilder, fieldDeclRef), + outToExpr ? &coercedArg : nullptr, fromInitializerListExpr, - ioArgIndexCandidate); + ioArgIndex); + + // No point in trying further if any argument fails + if (!argResult) + return false; if (coercedArg) - maybeArgList.add(coercedArg); - else - break; + { + coercedArgs.add(coercedArg); + } } + } + } + else + { + auto toTypeDeclRef = toDeclRefType->getDeclRef(); + if (auto toStructDeclRef = toTypeDeclRef.as()) + { + // We will try to coerce the initializer list into a struct following these steps: + // 1. Ensure our `StructDecl` has declaratations created for all auto-generated constructors + // 2. We have a `{}` (0 arguments), try to coerce + // 3. We have a `{arg1, arg2...}`, try to coerce - if (!allowCStyleInitList && maybeArgList.getCount() != ctorParamCount) - continue; + auto toStructDecl = toStructDeclRef.getDecl(); + // 1. Ensure our `StructDecl` has declaratations created for all auto-generated constructors + ensureDecl(toStructDecl, DeclCheckState::DefaultConstructorReadyForUse); - // Skip non-visible constructors. - if (!isDeclVisible(ctor)) + // 2. We have a `{}` (0 arguments), try to coerce + if (argCount == 0) { - // if an exact argument match with our init-list we know the user meant to use a - // member-wise constructor, error - if(ctorParamCount == Index(argCount)) - getSink()->diagnose(fromInitializerListExpr, Diagnostics::declIsNotVisible, ctor); - continue; + if (outToExpr) + { + *outToExpr = constructZeroInitListFunc(this, toStructDecl, toType, ConstructZeroInitListOptions::CheckToAvoidRecursion); + (*outToExpr)->loc = fromInitializerListExpr->loc; + } + return true; } + // 3. We have a `{arg1, arg2...}`, try to coerce + // + // For this situation we have more steps: + // a. Find constructor candidate for our particular init-list + // b. Collect and coerce init-list arguments into constructor parameters // c. Create InvokeExpr for our valid ConstructorDecl - // We cannot fail anymore, set ioArgIndex to the 'used up arg count'. - if (outToExpr) + List ctorList = _getCtorList(this->getASTBuilder(), this, toStructDecl, nullptr); + bool allowCStyleInitList = checkIfCStyleStruct(this, toStructDecl); + + List maybeArgList; + maybeArgList.reserve(argCount); + Index ioArgIndexMirror = ioArgIndex; + UInt ioArgIndexCandidate = 0; + + for (auto& ctor : ctorList) { - ioArgIndex = ioArgIndexCandidate; + // a. Find constructor candidate for our particular init-list - for (auto i : maybeArgList) - coercedArgs.add(i); + // Don't try to init default ctor with this logic + auto ctorParamCount = ctor->getParameters().getCount(); + if (ctorParamCount == 0) + continue; - List argTypes; - for (auto i : coercedArgs) - argTypes.add(i->type); + ioArgIndexCandidate = ioArgIndexMirror; + ioArgIndex = ctorParamCount; - auto* varExpr = getASTBuilder()->create(); - varExpr->type = (QualType)getASTBuilder()->getTypeType(toType); - varExpr->declRef = isDeclRefTypeOf(toType); - auto* constructorExpr = getASTBuilder()->create(); - constructorExpr->functionExpr = varExpr; - constructorExpr->arguments.addRange(coercedArgs); - auto resolvedConstructorExpr = CheckExpr(constructorExpr); + // if allowCStyleInitList, process any ctor which comes next using the most members possible. ioArgIndex may not be 0. + // if !allowCStyleInitList, process any ctor that exactly matched our argument count. ioArgIndex must start at 0. + if (!allowCStyleInitList && ctorParamCount != Index(argCount)) + continue; + + // b. Collect and coerce init-list arguments into constructor parameters + List maybeCandidate; + auto parameters = getParameters(m_astBuilder, ctor); + auto parametersCount = parameters.getCount(); + + for (auto index = coercedArgs.getCount(); index < parametersCount; index++) + { + // If we ran out of elements and allow using a c-style-partial-initialization-list, end early. + if ((Index)ioArgIndexCandidate > fromInitializerListExpr->args.getCount()) + break; + + auto ctorParam = parameters[index]; + auto paramType = ctorParam.getDecl()->type.type; + for (auto i : getMembersOfType(m_astBuilder, toStructDeclRef, MemberFilterStyle::Instance)) + if (i.getDecl()->type.type == paramType) + paramType = getType(m_astBuilder, i); + + Expr* coercedArg = nullptr; + _readValueFromInitializerList( + paramType, + &coercedArg, + fromInitializerListExpr, + ioArgIndexCandidate); + + if (coercedArg) + maybeArgList.add(coercedArg); + else + break; + } + + if (!allowCStyleInitList && maybeArgList.getCount() != ctorParamCount) + continue; + + // Skip non-visible constructors. + if (!isDeclVisible(ctor)) + { + // if an exact argument match with our init-list we know the user meant to use a + // member-wise constructor, error + if (ctorParamCount == Index(argCount)) + getSink()->diagnose(fromInitializerListExpr, Diagnostics::declIsNotVisible, ctor); + continue; + } + + // c. Create InvokeExpr for our valid ConstructorDecl + // We cannot fail anymore, set ioArgIndex to the 'used up arg count'. + if (outToExpr) + { + ioArgIndex = ioArgIndexCandidate; + + for (auto i : maybeArgList) + coercedArgs.add(i); + + List argTypes; + for (auto i : coercedArgs) + argTypes.add(i->type); + + auto* varExpr = getASTBuilder()->create(); + varExpr->type = (QualType)getASTBuilder()->getTypeType(toType); + varExpr->declRef = isDeclRefTypeOf(toType); + auto* constructorExpr = getASTBuilder()->create(); + constructorExpr->functionExpr = varExpr; + constructorExpr->arguments.addRange(coercedArgs); + auto resolvedConstructorExpr = CheckExpr(constructorExpr); - *outToExpr = resolvedConstructorExpr; + *outToExpr = resolvedConstructorExpr; + } + return true; } - return true; - } - // If we have a generic being compared to another generic (with different generic arguments) - // coerce logic will fail regardless of if generics are valid together. Example is below: - // - // MyStruct tmp = {MyStructBase(), 1}; // assume 'U' is unresolved at this point in time but equal to T - // - // To handle this since this is not verifiable coerce logic: - // 1. We need to ensure we don't have any matching constructors - // 2. if '1.' is true we can assign the possibly compatible generics and let generic resolution diagnose - // if something makes zero sense. + // If we have a generic being compared to another generic (with different generic arguments) + // coerce logic will fail regardless of if generics are valid together. Example is below: + // + // MyStruct tmp = {MyStructBase(), 1}; // assume 'U' is unresolved at this point in time but equal to T + // + // To handle this since this is not verifiable coerce logic: + // 1. We need to ensure we don't have any matching constructors + // 2. if '1.' is true we can assign the possibly compatible generics and let generic resolution diagnose + // if something makes zero sense. - if (auto toGenericType = _getGenericAppDeclRefType(toType)) - { - auto arg = fromInitializerListExpr->args[ioArgIndexMirror]; - if (auto fromGenericType = _getGenericAppDeclRefType(getType(m_astBuilder, arg))) + if (auto toGenericType = _getGenericAppDeclRefType(toType)) { - for (;;) + auto arg = fromInitializerListExpr->args[ioArgIndexMirror]; + if (auto fromGenericType = _getGenericAppDeclRefType(getType(m_astBuilder, arg))) { - if (toGenericType->getBase() != fromGenericType->getBase()) - break; + for (;;) + { + if (toGenericType->getBase() != fromGenericType->getBase()) + break; - ioArgIndex = ioArgIndexMirror; - *outToExpr = arg; - ioArgIndex++; - return true; + ioArgIndex = ioArgIndexMirror; + *outToExpr = arg; + ioArgIndex++; + return true; + } } } } @@ -687,14 +746,32 @@ namespace Slang !canCoerce(toType, fromInitializerListExpr->type, nullptr)) return _failedCoercion(toType, outToExpr, fromInitializerListExpr); - if(!_readAggregateValueFromInitializerList(toType, outToExpr, fromInitializerListExpr, argIndex)) + if(!_readAggregateValueFromInitializerList(toType, outToExpr, fromInitializerListExpr, argIndex)) return false; if(argIndex != argCount) { if( outToExpr ) { - getSink()->diagnose(fromInitializerListExpr, Diagnostics::tooManyInitializers, argCount, toType); + bool error = true; + // Try to use legacy struct logic if we have a 'struct' toType for Slang backwards compatability + if (auto declRefType = as(toType)) + { + if (declRefType->getDeclRef().as()) + { + // If we fail, pretend as if we never called this logic by throwing a regular error + // If we pass, warn + argIndex = 0; + _readAggregateValueFromInitializerList(toType, outToExpr, fromInitializerListExpr, argIndex); + if (argIndex == argCount) + { + getSink()->diagnose(fromInitializerListExpr, Diagnostics::usingLegacyInitListStructLogic); + return true; + } + } + } + // If we fail with legacy logic, error + getSink()->diagnose(fromInitializerListExpr, Diagnostics::cannotFindMatchingInitListToConstructorCount, argCount, toType); } } diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index c3142e753b..42a7a60e04 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -1506,6 +1506,7 @@ namespace Slang /// If the routine fails and `outToExpr` is non-null, /// then a suitable diagnostic will be emitted. /// + template bool _readValueFromInitializerList( Type* toType, Expr** outToExpr, @@ -1531,6 +1532,7 @@ namespace Slang /// If the routine fails and `outToExpr` is non-null, /// then a suitable diagnostic will be emitted. /// + template bool _readAggregateValueFromInitializerList( Type* inToType, Expr** outToExpr, diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 05bdf63cde..0c9f7acf8f 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -521,11 +521,12 @@ DIAGNOSTIC(30400, Error, genericTypeNeedsArgs, "generic type '$0' used without a DIAGNOSTIC(30401, Error, invalidTypeForConstraint, "type '$0' cannot be used as a constraint.") // 305xx: initializer lists -DIAGNOSTIC(30500, Error, tooManyInitializers, "cannot find matching constructor to call with arguments count of '$0' for '$1'") +DIAGNOSTIC(30500, Error, cannotFindMatchingInitListToConstructorCount, "cannot find matching constructor to call with arguments count of '$0' for '$1'") DIAGNOSTIC(30501, Error, cannotUseInitializerListForArrayOfUnknownSize, "cannot use initializer list for array of statically unknown size '$0'") DIAGNOSTIC(30502, Error, cannotUseInitializerListForVectorOfUnknownSize, "cannot use initializer list for vector of statically unknown size '$0'") DIAGNOSTIC(30503, Error, cannotUseInitializerListForMatrixOfUnknownSize, "cannot use initializer list for matrix of statically unknown size '$0' rows") DIAGNOSTIC(30504, Error, cannotUseInitializerListForType, "cannot use initializer list for type '$0'") +DIAGNOSTIC(30505, Warning, usingLegacyInitListStructLogic, "detected deprecated legacy initializer-list (`{...}`) resolution logic, we advise following proper initializer-list rules as per Slang's user-guide") // 3062x: variables DIAGNOSTIC(30620, Error, varWithoutTypeMustHaveInitializer, "a variable declaration without an initial-value expression must be given an explicit type") diff --git a/tests/language-feature/initializer-lists/deprecated-init-list-behavior.slang b/tests/language-feature/initializer-lists/deprecated-init-list-behavior.slang new file mode 100644 index 0000000000..0dbf2da46f --- /dev/null +++ b/tests/language-feature/initializer-lists/deprecated-init-list-behavior.slang @@ -0,0 +1,38 @@ +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute + +struct InnerTest +{ + uint a; +}; + +struct Test +{ + InnerTest a; + uint b; + float2 c; +}; + +struct TestOuter : Test +{ + __init(float val) + { + } +}; + +//CHECK: warning 30505 +//CHECK: computeMain + +RWStructuredBuffer outputBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + TestOuter test = {1, 1, float3(1).x, float3(1).z}; + + outputBuffer[0] = true + && test.a.a == 1 + && test.b == 1 + && test.c[0] == 1 + && test.c[1] == 1 + ; +} \ No newline at end of file From ba3a91dfcae0fb4bda0536c5dfc6dd1bb41999f5 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:03:33 -0400 Subject: [PATCH 088/100] fix now-invalid tests to be valid --- source/slang/slang-check-conversion.cpp | 1 + ... => deprecated-init-list-behavior-1.slang} | 0 ... => deprecated-init-list-behavior-2.slang} | 3 +- .../dont-allow-cstyle-init-list-1.slang | 31 ------------------- 4 files changed, 3 insertions(+), 32 deletions(-) rename tests/language-feature/initializer-lists/{deprecated-init-list-behavior.slang => deprecated-init-list-behavior-1.slang} (100%) rename tests/language-feature/initializer-lists/{dont-allow-cstyle-init-list-2.slang => deprecated-init-list-behavior-2.slang} (92%) delete mode 100644 tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-1.slang diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 3a57ec1f2d..73addb865c 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -755,6 +755,7 @@ namespace Slang { bool error = true; // Try to use legacy struct logic if we have a 'struct' toType for Slang backwards compatability + // Note: if we remove this entire `if` block, "LegacyLogic" will be no-longer be enabled if (auto declRefType = as(toType)) { if (declRefType->getDeclRef().as()) diff --git a/tests/language-feature/initializer-lists/deprecated-init-list-behavior.slang b/tests/language-feature/initializer-lists/deprecated-init-list-behavior-1.slang similarity index 100% rename from tests/language-feature/initializer-lists/deprecated-init-list-behavior.slang rename to tests/language-feature/initializer-lists/deprecated-init-list-behavior-1.slang diff --git a/tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-2.slang b/tests/language-feature/initializer-lists/deprecated-init-list-behavior-2.slang similarity index 92% rename from tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-2.slang rename to tests/language-feature/initializer-lists/deprecated-init-list-behavior-2.slang index 903d9c164d..0ed08f8cc3 100644 --- a/tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-2.slang +++ b/tests/language-feature/initializer-lists/deprecated-init-list-behavior-2.slang @@ -12,7 +12,8 @@ struct Test }; -//ERROR: error 30500 +//CHECK: warning 30505 +//CHECK: computeMain RWStructuredBuffer outputBuffer; diff --git a/tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-1.slang b/tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-1.slang deleted file mode 100644 index 682eaac3aa..0000000000 --- a/tests/language-feature/initializer-lists/dont-allow-cstyle-init-list-1.slang +++ /dev/null @@ -1,31 +0,0 @@ -//TEST:SIMPLE(filecheck=ERROR): -target hlsl -entry computeMain -stage compute - -public struct Test -{ - // note: we need an initExpr here for an error because else Slang will disallow - // synthisis of a 'public' constructor, meaning nothing has to fail. - internal uint a = 5; - public uint b; -}; - - -//ERROR: error 30500 - -RWStructuredBuffer outputBuffer; - -[numthreads(1, 1, 1)] -void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - Test test[3] = {1, 2, 3, 4, 5, 6}; - - outputBuffer[0] = true - && test[0].a == 1 - && test[0].b == 2 - - && test[1].a == 1 - && test[1].b == 2 - - && test[2].a == 1 - && test[2].b == 2 - ; -} \ No newline at end of file From 852bbc36f1148df5f596eb0201c2bd8ea355fbf4 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:08:24 -0400 Subject: [PATCH 089/100] fix warning --- source/slang/slang-check-conversion.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 73addb865c..1aadae52a8 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -753,7 +753,6 @@ namespace Slang { if( outToExpr ) { - bool error = true; // Try to use legacy struct logic if we have a 'struct' toType for Slang backwards compatability // Note: if we remove this entire `if` block, "LegacyLogic" will be no-longer be enabled if (auto declRefType = as(toType)) From af2ef090d035cbf61e1411ffe1639272165e55a9 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:18:08 -0400 Subject: [PATCH 090/100] fix incorrect test --- .../initializer-lists/deprecated-init-list-behavior-2.slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/language-feature/initializer-lists/deprecated-init-list-behavior-2.slang b/tests/language-feature/initializer-lists/deprecated-init-list-behavior-2.slang index 0ed08f8cc3..1a4a80faa9 100644 --- a/tests/language-feature/initializer-lists/deprecated-init-list-behavior-2.slang +++ b/tests/language-feature/initializer-lists/deprecated-init-list-behavior-2.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE(filecheck=ERROR): -target hlsl -entry computeMain -stage compute +//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry computeMain -stage compute struct Test { From e2cc2339893c4c0bf33b91b563fbef667d56119f Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 6 Sep 2024 16:33:07 -0400 Subject: [PATCH 091/100] cleanup code & comments --- source/slang/slang-ast-decl.h | 2 +- source/slang/slang-ast-modifier.h | 2 +- source/slang/slang-check-conversion.cpp | 14 +++++++------- source/slang/slang-check-decl.cpp | 9 ++++----- source/slang/slang-ir.cpp | 8 ++++---- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h index 93f8ad9251..226b2d66f8 100644 --- a/source/slang/slang-ast-decl.h +++ b/source/slang/slang-ast-decl.h @@ -379,7 +379,7 @@ enum class ConstructorTags : int MemberwiseCtorForPublicVisibility = 1 << 1, /// Derived classes will call this ctor if they need a memberwise ctor for public and internal members. - /// This ctor may be equal to 'isMemberwiseCtorForPublicVisibility' + /// A ctor with `MemberwiseCtorForInternalVisibility` may also contain 'isMemberwiseCtorForPublicVisibility' MemberwiseCtorForInternalVisibility = 1 << 2, }; diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index ec537d4bf2..d7a46e707d 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -38,7 +38,7 @@ class ToBeSynthesizedModifier : public Modifier {SLANG_AST_CLASS(ToBeSynthesized // Marks that the definition of a decl is synthesized. class SynthesizedModifier : public Modifier { SLANG_AST_CLASS(SynthesizedModifier) }; -// Marks that the definition of a decl is synthesized. +// Marks that the definition of a decl is our $ZeroInit function. class ZeroInitModifier : public Modifier { SLANG_AST_CLASS(ZeroInitModifier) }; // Marks a synthesized variable as local temporary variable. diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 1aadae52a8..c2ff0dd4b4 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -68,7 +68,6 @@ namespace Slang return true; } - // bool isSameSimpleExprType(Type* type1, Type* type2) { if (as(type1) && as(type2)) return true; @@ -111,8 +110,8 @@ namespace Slang if (toType->equals(fromExpr->type)) return true; - // `vector` and `vector` may not be copyable, but, we have no choice in this senario but to assume coerce logic - // can resolve such situations + // `vector` and `vector` may not be equal types, but, we have no choice in this senario but to assume coerce logic + // can resolve such situations, otherwise we need to fail if (isSameSimpleExprType(toType, fromExpr->type)) return true; @@ -329,6 +328,7 @@ namespace Slang { // TODO(tfoley): If we can compute the size of the array statically, // then we want to check that there aren't too many initializers present + auto toElementType = toArrayType->getElementType(); if(!toArrayType->isUnsized()) { @@ -618,7 +618,7 @@ namespace Slang } // c. Create InvokeExpr for our valid ConstructorDecl - // We cannot fail anymore, set ioArgIndex to the 'used up arg count'. + // We cannot fail anymore, set `ioArgIndex` to the 'used up arg count'. if (outToExpr) { ioArgIndex = ioArgIndexCandidate; @@ -646,12 +646,12 @@ namespace Slang // If we have a generic being compared to another generic (with different generic arguments) // coerce logic will fail regardless of if generics are valid together. Example is below: // - // MyStruct tmp = {MyStructBase(), 1}; // assume 'U' is unresolved at this point in time but equal to T + // MyStruct tmp = {MyStructBase(), 1}; // Assume 'U' is unresolved at this point in time but equal to T // // To handle this since this is not verifiable coerce logic: // 1. We need to ensure we don't have any matching constructors - // 2. if '1.' is true we can assign the possibly compatible generics and let generic resolution diagnose - // if something makes zero sense. + // 2. if '1.' is true we can assign the possibly compatible generics and let generic resolution + // diagnose an error down the line if types are in-compatible if (auto toGenericType = _getGenericAppDeclRefType(toType)) { diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 5142ab78fd..5acd302158 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -1866,7 +1866,7 @@ namespace Slang addModifier(ctor, m_astBuilder->create()); ctor->addOption(ConstructorTags::Synthesized); - // kIROp_TorchTensorType must only refer to its own type through Host functions + // kIROp_TorchTensorType can only be used in host-callable functions if(auto intrinsicType = decl->findModifier()) if(intrinsicType->irOp == kIROp_TorchTensorType) addModifier(ctor, m_astBuilder->create()); @@ -1961,8 +1961,6 @@ namespace Slang varDecl->initExpr = constructDefaultInitExprForVar(this, varDecl->type, varDecl); } - auto type = varDecl->getType(); - if (auto initExpr = varDecl->initExpr) { // Disable the short-circuiting for static const variable init expression @@ -2010,12 +2008,12 @@ namespace Slang // and filtering them to ones that are applicable // to our "call site" with zero arguments. // - OverloadResolveContext overloadContext; overloadContext.loc = varDecl->nameAndLoc.loc; overloadContext.mode = OverloadResolveContext::Mode::JustTrying; overloadContext.sourceScope = m_outerScope; + auto type = varDecl->getType(); ImplicitCastMethodKey key = ImplicitCastMethodKey(QualType(), type, nullptr); auto ctorMethod = getShared()->tryGetImplicitCastMethod(key); if (ctorMethod) @@ -2513,7 +2511,6 @@ namespace Slang } } - // Annotate ctor as a memberwise ctor. A non synthisized function may be annotated as a memberwise ctor // if it has a compatible parameter list with a memberwise ctor. void _annotateMemberwiseCtorWithVisibility(ConstructorDecl* ctor, DeclVisibility visibility) @@ -2644,6 +2641,7 @@ namespace Slang // $ZeroInit is a synthisized static-function only used In 2 cases: // 1. if `{}` is used inside a `__init()` // 2. if `{}` is used and a user has a 'synthisized __init()` + // // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. { auto zeroInitFunc = m_astBuilder->create(); @@ -8136,6 +8134,7 @@ namespace Slang // auto structDeclType = DeclRefType::create(m_astBuilder, structDecl); + // Collect ctor info struct DeclAndCtorInfo { diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index ce244262ba..633451e1e3 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -3741,11 +3741,11 @@ namespace Slang // Slang generally detects recursive type-uses in IR, // This means that DefaultConstruct may crash unless we // track visited types with `visitedTypes.contains(type)` - // to avoid infinite looping of type-checks + // to avoid infinite looping of type-checks. // - // Slang may be asked to default init a `RWTexture2D`. - // If so, `isResourceType(type)` ensures we don't generate - // garbage/ + // Slang may be asked to default init a `RWTexture2D`, + // if so, adding `isResourceType(type)` ensures we don't + // generate garbage for resource types. if (visitedTypes.contains(type) || isResourceType(type)) return emitUndefined(type); visitedTypes.add(type); From c0e59e84f30557389d8dd895198c068c219fb6f7 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Fri, 6 Sep 2024 19:27:13 -0400 Subject: [PATCH 092/100] clean up and cover all cases of `{...}` failiure so that we run legacy logic. --- source/slang/slang-check-conversion.cpp | 188 +++++++++++++----------- 1 file changed, 105 insertions(+), 83 deletions(-) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index c2ff0dd4b4..9bbea118a3 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -15,7 +15,7 @@ namespace Slang ConversionCost SemanticsVisitor::getImplicitConversionCost( Decl* decl) { - if(auto modifier = decl->findModifier()) + if (auto modifier = decl->findModifier()) { return modifier->cost; } @@ -35,33 +35,33 @@ namespace Slang } bool SemanticsVisitor::isEffectivelyScalarForInitializerLists( - Type* type) + Type* type) { - if(as(type)) return false; - if(as(type)) return false; - if(as(type)) return false; + if (as(type)) return false; + if (as(type)) return false; + if (as(type)) return false; - if(as(type)) + if (as(type)) { return true; } - if(as(type)) + if (as(type)) { return true; } - if(as(type)) + if (as(type)) { return true; } - if(as(type)) + if (as(type)) { return true; } - if(auto declRefType = as(type)) + if (auto declRefType = as(type)) { - if(as(declRefType->getDeclRef())) + if (as(declRefType->getDeclRef())) return false; } @@ -78,12 +78,12 @@ namespace Slang } bool SemanticsVisitor::shouldUseInitializerDirectly( - Type* toType, - Expr* fromExpr) + Type* toType, + Expr* fromExpr) { // A nested initializer list should always be used directly. // - if(as(fromExpr)) + if (as(fromExpr)) { return true; } @@ -91,14 +91,14 @@ namespace Slang // If the desired type is a scalar, then we should always initialize // directly, since it isn't an aggregate. // - if(isEffectivelyScalarForInitializerLists(toType)) + if (isEffectivelyScalarForInitializerLists(toType)) return true; // If the type we are initializing isn't effectively scalar, // but the initialization expression *is*, then it doesn't // seem like direct initialization is intended. // - if(isEffectivelyScalarForInitializerLists(fromExpr->type)) + if (isEffectivelyScalarForInitializerLists(fromExpr->type)) return false; // If 2 types are "broadly equal" we know the types can be coerced directly @@ -120,16 +120,16 @@ namespace Slang template bool SemanticsVisitor::_readValueFromInitializerList( - Type* toType, - Expr** outToExpr, + Type* toType, + Expr** outToExpr, InitializerListExpr* fromInitializerListExpr, - UInt &ioInitArgIndex) + UInt& ioInitArgIndex) { // First, we will check if we have run out of arguments // on the initializer list. // UInt initArgCount = fromInitializerListExpr->args.getCount(); - if(ioInitArgIndex >= initArgCount) + if (ioInitArgIndex >= initArgCount) { // If we are at the end of the initializer list, // then our ability to read an argument depends @@ -148,7 +148,7 @@ namespace Slang // for aggregate initialization. // auto firstInitExpr = fromInitializerListExpr->args[ioInitArgIndex]; - if(shouldUseInitializerDirectly(toType, firstInitExpr) && canCoerce(toType, firstInitExpr->type, firstInitExpr)) + if (shouldUseInitializerDirectly(toType, firstInitExpr) && canCoerce(toType, firstInitExpr->type, firstInitExpr)) { ioInitArgIndex++; return _coerce( @@ -164,7 +164,7 @@ namespace Slang // expressions, then everything could be thrown off and we // shouldn't keep trying to read arguments. // - if( IsErrorExpr(firstInitExpr) ) + if (IsErrorExpr(firstInitExpr)) { // Stop reading arguments, as if we'd reached // the end of the list. @@ -186,17 +186,17 @@ namespace Slang DeclRefType* findBaseStructType(ASTBuilder* astBuilder, DeclRef structTypeDeclRef) { auto inheritanceDecl = getMembersOfType(astBuilder, structTypeDeclRef).getFirstOrNull(); - if(!inheritanceDecl) + if (!inheritanceDecl) return nullptr; auto baseType = getBaseType(astBuilder, inheritanceDecl); auto baseDeclRefType = as(baseType); - if(!baseDeclRefType) + if (!baseDeclRefType) return nullptr; auto baseDeclRef = baseDeclRefType->getDeclRef(); auto baseStructDeclRef = baseDeclRef.as(); - if(!baseStructDeclRef) + if (!baseStructDeclRef) return nullptr; return baseDeclRefType; @@ -235,10 +235,10 @@ namespace Slang template bool SemanticsVisitor::_readAggregateValueFromInitializerList( - Type* inToType, - Expr** outToExpr, + Type* inToType, + Expr** outToExpr, InitializerListExpr* fromInitializerListExpr, - UInt &ioArgIndex) + UInt& ioArgIndex) { auto toType = inToType; UInt argCount = fromInitializerListExpr->args.getCount(); @@ -247,18 +247,18 @@ namespace Slang // we will collect the new arguments here List coercedArgs; - if(isEffectivelyScalarForInitializerLists(toType)) + if (isEffectivelyScalarForInitializerLists(toType)) { // For any type that is effectively a non-aggregate, // we expect to read a single value from the initializer list // - if(ioArgIndex < argCount) + if (ioArgIndex < argCount) { auto arg = fromInitializerListExpr->args[ioArgIndex++]; if (!canCoerce(toType, arg->type, nullptr)) { - if(outToExpr) + if (outToExpr) *outToExpr = arg; return true; } @@ -291,21 +291,21 @@ namespace Slang UInt elementCount = 0; if (auto constElementCount = as(toElementCount)) { - elementCount = (UInt) constElementCount->getValue(); + elementCount = (UInt)constElementCount->getValue(); } else { // We don't know the element count statically, // so what are we supposed to be doing? // - if(outToExpr) + if (outToExpr) { getSink()->diagnose(fromInitializerListExpr, Diagnostics::cannotUseInitializerListForVectorOfUnknownSize, toElementCount); } return false; } - for(UInt ee = 0; ee < elementCount; ++ee) + for (UInt ee = 0; ee < elementCount; ++ee) { Expr* coercedArg = nullptr; bool argResult = _readValueFromInitializerList( @@ -315,22 +315,22 @@ namespace Slang ioArgIndex); // No point in trying further if any argument fails - if(!argResult) + if (!argResult) return false; - if( coercedArg ) + if (coercedArg) { coercedArgs.add(coercedArg); } } } - else if(auto toArrayType = as(toType)) + else if (auto toArrayType = as(toType)) { // TODO(tfoley): If we can compute the size of the array statically, // then we want to check that there aren't too many initializers present auto toElementType = toArrayType->getElementType(); - if(!toArrayType->isUnsized()) + if (!toArrayType->isUnsized()) { auto toElementCount = toArrayType->getElementCount(); @@ -340,21 +340,21 @@ namespace Slang UInt elementCount = 0; if (auto constElementCount = as(toElementCount)) { - elementCount = (UInt) constElementCount->getValue(); + elementCount = (UInt)constElementCount->getValue(); } else { // We don't know the element count statically, // so what are we supposed to be doing? // - if(outToExpr) + if (outToExpr) { getSink()->diagnose(fromInitializerListExpr, Diagnostics::cannotUseInitializerListForArrayOfUnknownSize, toElementCount); } return false; } - for(UInt ee = 0; ee < elementCount; ++ee) + for (UInt ee = 0; ee < elementCount; ++ee) { Expr* coercedArg = nullptr; bool argResult = _readValueFromInitializerList( @@ -364,10 +364,10 @@ namespace Slang ioArgIndex); // No point in trying further if any argument fails - if(!argResult) + if (!argResult) return false; - if( coercedArg ) + if (coercedArg) { coercedArgs.add(coercedArg); } @@ -380,7 +380,7 @@ namespace Slang // the element count. // UInt elementCount = 0; - while(ioArgIndex < argCount) + while (ioArgIndex < argCount) { Expr* coercedArg = nullptr; bool argResult = _readValueFromInitializerList( @@ -390,12 +390,12 @@ namespace Slang ioArgIndex); // No point in trying further if any argument fails - if(!argResult) + if (!argResult) return false; elementCount++; - if( coercedArg ) + if (coercedArg) { coercedArgs.add(coercedArg); } @@ -407,7 +407,7 @@ namespace Slang m_astBuilder->getIntVal(m_astBuilder->getIntType(), elementCount)); } } - else if(auto toMatrixType = as(toType)) + else if (auto toMatrixType = as(toType)) { // In the general case, the initializer list might comprise // both vectors and scalars. @@ -429,21 +429,21 @@ namespace Slang if (auto constRowCount = as(toMatrixType->getRowCount())) { - rowCount = (UInt) constRowCount->getValue(); + rowCount = (UInt)constRowCount->getValue(); } else { // We don't know the element count statically, // so what are we supposed to be doing? // - if(outToExpr) + if (outToExpr) { getSink()->diagnose(fromInitializerListExpr, Diagnostics::cannotUseInitializerListForMatrixOfUnknownSize, toMatrixType->getRowCount()); } return false; } - for(UInt rr = 0; rr < rowCount; ++rr) + for (UInt rr = 0; rr < rowCount; ++rr) { Expr* coercedArg = nullptr; bool argResult = _readValueFromInitializerList( @@ -453,16 +453,16 @@ namespace Slang ioArgIndex); // No point in trying further if any argument fails - if(!argResult) + if (!argResult) return false; - if( coercedArg ) + if (coercedArg) { coercedArgs.add(coercedArg); } } } - else if(auto toDeclRefType = as(toType)) + else if (auto toDeclRefType = as(toType)) { // We allow using legacy "init list" logic as a backup if something fails if constexpr (UseLegacyLogic) @@ -517,7 +517,7 @@ namespace Slang } } } - } + } else { auto toTypeDeclRef = toDeclRefType->getDeclRef(); @@ -680,7 +680,7 @@ namespace Slang // list invalid if we are trying to read something // off of it that wasn't handled by the cases above. // - if(outToExpr) + if (outToExpr) { getSink()->diagnose(fromInitializerListExpr, Diagnostics::cannotUseInitializerListForType, inToType); } @@ -690,7 +690,7 @@ namespace Slang // We were able to coerce all the arguments given, and so // we need to construct a suitable expression to remember the result // - if(outToExpr) + if (outToExpr) { auto toInitializerListExpr = m_astBuilder->create(); toInitializerListExpr->loc = fromInitializerListExpr->loc; @@ -702,10 +702,10 @@ namespace Slang // if (auto func = getParentFuncOfVisitor()) { - if (func->findModifier() && + if (func->findModifier() && !isTypeDifferentiable(toType)) { - for (auto &arg : toInitializerListExpr->args) + for (auto& arg : toInitializerListExpr->args) { if (isTypeDifferentiable(arg->type.type)) { @@ -724,9 +724,32 @@ namespace Slang return true; } + void _maybeRunLegacyLogic( + SemanticsVisitor* visitor, + Type* toType, + Expr** outToExpr, + InitializerListExpr* fromInitializerListExpr, + bool& result, + UInt& argIndex, + bool& ranLegacyLogic + ) + { + // Try to use legacy struct logic if we have a 'struct' toType for Slang backwards compatability + // Note: if we remove this entire `if` block, "LegacyLogic" will be no-longer be enabled + if (auto declRefType = as(toType)) + { + if (declRefType->getDeclRef().as()) + { + argIndex = 0; + ranLegacyLogic = true; + result = visitor->_readAggregateValueFromInitializerList(toType, outToExpr, fromInitializerListExpr, argIndex); + } + } + } + bool SemanticsVisitor::_coerceInitializerList( - Type* toType, - Expr** outToExpr, + Type* toType, + Expr** outToExpr, InitializerListExpr* fromInitializerListExpr) { UInt argCount = fromInitializerListExpr->args.getCount(); @@ -742,39 +765,38 @@ namespace Slang // If this isn't prohibited, then we can proceed to try and coerce from // the initializer list itself; assuming that coercion is closed under // composition this shouldn't fail. - if(!as(fromInitializerListExpr->type) && - !canCoerce(toType, fromInitializerListExpr->type, nullptr)) + if (!as(fromInitializerListExpr->type) && + !canCoerce(toType, fromInitializerListExpr->type, nullptr)) return _failedCoercion(toType, outToExpr, fromInitializerListExpr); - if(!_readAggregateValueFromInitializerList(toType, outToExpr, fromInitializerListExpr, argIndex)) - return false; + // If we fail, try to run legacy logic. + bool usedLegacy = false; + bool result = _readAggregateValueFromInitializerList(toType, outToExpr, fromInitializerListExpr, argIndex); + // Note: if we remove this entire `if` block for a `return false`, "LegacyLogic" will be no-longer be enabled for "failed" case + if(!result) + { + _maybeRunLegacyLogic(this, toType, outToExpr, fromInitializerListExpr, result, argIndex, usedLegacy); + if (!result) + return false; + } if(argIndex != argCount) { if( outToExpr ) { - // Try to use legacy struct logic if we have a 'struct' toType for Slang backwards compatability - // Note: if we remove this entire `if` block, "LegacyLogic" will be no-longer be enabled - if (auto declRefType = as(toType)) - { - if (declRefType->getDeclRef().as()) - { - // If we fail, pretend as if we never called this logic by throwing a regular error - // If we pass, warn - argIndex = 0; - _readAggregateValueFromInitializerList(toType, outToExpr, fromInitializerListExpr, argIndex); - if (argIndex == argCount) - { - getSink()->diagnose(fromInitializerListExpr, Diagnostics::usingLegacyInitListStructLogic); - return true; - } - } - } - // If we fail with legacy logic, error - getSink()->diagnose(fromInitializerListExpr, Diagnostics::cannotFindMatchingInitListToConstructorCount, argCount, toType); + // Note: if we remove this entire `if` block, "LegacyLogic" will be no-longer be enabled for "too-many-arg" case + if (!usedLegacy) + _maybeRunLegacyLogic(this, toType, outToExpr, fromInitializerListExpr, result, argIndex, usedLegacy); + // If we fail without/with legacy logic, error as usual + if (argIndex != argCount) + getSink()->diagnose(fromInitializerListExpr, Diagnostics::cannotFindMatchingInitListToConstructorCount, argCount, toType); } } + // Warn that legacy logic is the reason for code to compile + if (usedLegacy) + getSink()->diagnose(fromInitializerListExpr, Diagnostics::usingLegacyInitListStructLogic); + return true; } From 54014949789e700a589f5eea098443f3e2bc337c Mon Sep 17 00:00:00 2001 From: kaizhangNV Date: Thu, 19 Sep 2024 12:08:34 -0700 Subject: [PATCH 093/100] fix easy comments --- source/slang/slang-ast-builder.h | 10 ++++++ source/slang/slang-check-conversion.cpp | 2 +- source/slang/slang-check-decl.cpp | 5 +-- source/slang/slang-check-impl.h | 2 +- source/slang/slang-constructor-utility.cpp | 41 ++++++++++++---------- 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/source/slang/slang-ast-builder.h b/source/slang/slang-ast-builder.h index 08951513dc..75c90e27a5 100644 --- a/source/slang/slang-ast-builder.h +++ b/source/slang/slang-ast-builder.h @@ -80,6 +80,15 @@ class SharedASTBuilder : public RefObject } return m_thisTypeName; } + + Name* getCtorName() + { + if (!m_ctorName) + { + m_ctorName = getNamePool()->getName("$init"); + } + return m_ctorName; + } protected: // State shared between ASTBuilders @@ -114,6 +123,7 @@ class SharedASTBuilder : public RefObject NamePool* m_namePool = nullptr; Name* m_thisTypeName = nullptr; + Name* m_ctorName = nullptr; // This is a private builder used for these shared types ASTBuilder* m_astBuilder = nullptr; diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 9bbea118a3..44d4cfd830 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -550,7 +550,7 @@ namespace Slang // b. Collect and coerce init-list arguments into constructor parameters // c. Create InvokeExpr for our valid ConstructorDecl List ctorList = _getCtorList(this->getASTBuilder(), this, toStructDecl, nullptr); - bool allowCStyleInitList = checkIfCStyleStruct(this, toStructDecl); + bool allowCStyleInitList = isCStyleStructDecl(this, toStructDecl, ctorList); List maybeArgList; maybeArgList.reserve(argCount); diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 32fe693b1f..7d0a41094e 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2798,7 +2798,7 @@ namespace Slang // `checkIfCStyleStruct` must check after we add all possible Ctors. // If we are a CStyleStruct add DefaultConstructExpr to all params (excluding arg 0) - bool isCStyleStruct = checkIfCStyleStruct(this, structDecl); + bool isCStyleStruct = isCStyleStructDecl(this, structDecl, ctorList); if (isCStyleStruct && generatedMemberwiseCtors.getCount() > 0) { // We know the user provided 0 non-default ctor's, we only had a chance to generate non default Ctors above in this AST pass. @@ -8299,6 +8299,7 @@ namespace Slang return ctor->containsOption(ConstructorTags::Synthesized) && ctor->getParameters().getCount() != 0 && !allParamHaveInitExpr(ctor); + // return ctor->findModifier(); } template @@ -8766,7 +8767,7 @@ namespace Slang } // Compiler generated ctor may be destroyed - bool destroyedDefaultCtor = false; + bool destroyedDefaultCtor = false; if(structDeclInfo.m_defaultCtor && structDeclInfo.m_defaultCtor->containsOption(ConstructorTags::Synthesized)) { diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 334737c97e..265b00ca2c 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -3037,7 +3037,7 @@ namespace Slang Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructZeroInitListOptions options); FuncDecl* findZeroInitListFunc(StructDecl* structDecl); - bool checkIfCStyleStruct(SemanticsVisitor* visitor, StructDecl* decl); + bool isCStyleStructDecl(SemanticsVisitor* visitor, StructDecl* decl, List const& ctorList); DefaultConstructExpr* createDefaultConstructExprForType(ASTBuilder* m_astBuilder, QualType type, SourceLoc loc); diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index 76bdfcc9ae..6d42c9284b 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -12,23 +12,27 @@ namespace Slang return defaultConstructExpr; } + bool allParamHaveInitExpr(ConstructorDecl* ctor) + { + for (auto i : ctor->getParameters()) + if (!i->initExpr) + return false; + return true; + } + ConstructorDecl* _getDefaultCtor(StructDecl* structDecl) { for (auto ctor : structDecl->getMembersOfType()) { - if (!ctor->body || ctor->members.getCount() != 0) + // 1. default ctor must have definition + // 2. default ctor must have no parameters or all parameters have init expr + if (!ctor->body || (ctor->members.getCount() != 0 && !allParamHaveInitExpr(ctor))) continue; return ctor; } return nullptr; } - bool allParamHaveInitExpr(ConstructorDecl* ctor) - { - for (auto i : ctor->getParameters()) - if (!i->initExpr) - return false; - return true; - } + List _getCtorList(ASTBuilder* m_astBuilder, SemanticsVisitor* visitor, StructDecl* structDecl, ConstructorDecl** defaultCtorOut) { List ctorList; @@ -36,7 +40,7 @@ namespace Slang auto ctorLookupResult = lookUpMember( m_astBuilder, visitor, - visitor->getName("$init"), + m_astBuilder->getSharedASTBuilder()->getCtorName(), DeclRefType::create(m_astBuilder, structDecl), structDecl->ownedScope, LookupMask::Function, @@ -63,7 +67,7 @@ namespace Slang return ctorList; } - for (auto m : ctorLookupResult.items) + for (auto m : ctorLookupResult) { lookupResultHandle(m); } @@ -151,7 +155,7 @@ namespace Slang return nullptr; } - Expr* _constructZeroInitListFuncMakeDefaultCtor(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructorDecl* defaultCtor) + Expr* constructDefaultCtorInvocationExpr(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructorDecl* defaultCtor) { auto* invoke = visitor->getASTBuilder()->create(); auto member = visitor->getASTBuilder()->getMemberDeclRef(structDecl->getDefaultDeclRef(), defaultCtor); @@ -192,34 +196,34 @@ namespace Slang } } if(canCreateCtor) - return _constructZeroInitListFuncMakeDefaultCtor(visitor, structDecl, structDeclType, defaultCtor); + return constructDefaultCtorInvocationExpr(visitor, structDecl, structDeclType, defaultCtor); } // 2. - if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) + if (auto defaultInitFunc = findZeroInitListFunc(structDecl)) { auto* invoke = visitor->getASTBuilder()->create(); DeclRef member; auto declRefType = as(structDeclType); if(declRefType && as(declRefType->getDeclRefBase())) - member = visitor->getASTBuilder()->getMemberDeclRef(as(declRefType->getDeclRefBase()), zeroInitListFunc); + member = visitor->getASTBuilder()->getMemberDeclRef(as(declRefType->getDeclRefBase()), defaultInitFunc); else - member = visitor->getASTBuilder()->getMemberDeclRef(structDecl, zeroInitListFunc); + member = visitor->getASTBuilder()->getMemberDeclRef(structDecl, defaultInitFunc); - invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, zeroInitListFunc->getName(), zeroInitListFunc->loc, nullptr); + invoke->functionExpr = visitor->ConstructDeclRefExpr(member, nullptr, defaultInitFunc->getName(), defaultInitFunc->loc, nullptr); invoke->type = structDeclType; return invoke; } // 3. if (defaultCtor) - return _constructZeroInitListFuncMakeDefaultCtor(visitor, structDecl, structDeclType, defaultCtor); + return constructDefaultCtorInvocationExpr(visitor, structDecl, structDeclType, defaultCtor); // 4. return createDefaultConstructExprForType(visitor->getASTBuilder(), QualType(structDeclType), {}); } - bool checkIfCStyleStruct(SemanticsVisitor* visitor, StructDecl* structDecl) + bool isCStyleStructDecl(SemanticsVisitor* visitor, StructDecl* structDecl, List const& ctorList) { // CStyleStruct follows the following rules: // 1. Does not contain a non 'Synthesized' Ctor (excluding 'DefaultCtor') @@ -236,7 +240,6 @@ namespace Slang return *isCStyleStruct; // Add to IsCStyleStruct cache - auto ctorList = _getCtorList(visitor->getASTBuilder(), visitor, structDecl, nullptr); int nonDefaultInitCount = 0; for (auto i : ctorList) { From 39268d6af6557f57a98921dfcd2fd028ee8c65d8 Mon Sep 17 00:00:00 2001 From: kaizhangNV Date: Thu, 19 Sep 2024 14:04:00 -0700 Subject: [PATCH 094/100] refactor _getDefaultCtor --- source/slang/slang-check-decl.cpp | 1 - source/slang/slang-constructor-utility.cpp | 19 ++++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 7d0a41094e..098c034637 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -8299,7 +8299,6 @@ namespace Slang return ctor->containsOption(ConstructorTags::Synthesized) && ctor->getParameters().getCount() != 0 && !allParamHaveInitExpr(ctor); - // return ctor->findModifier(); } template diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index 6d42c9284b..39108bdde0 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -20,15 +20,24 @@ namespace Slang return true; } + static inline bool _isDefaultCtor(ConstructorDecl* ctor) + { + // 1. default ctor must have definition + // 2. either 2.1 or 2.2 is safisfied + // 2.1. default ctor must have no parameters + // 2.2. default ctor can have parameters, but all parameters have init expr (Because we won't differentiate this case from 2.) + if (!ctor->body || (ctor->members.getCount() != 0 && !allParamHaveInitExpr(ctor))) + return false; + + return true; + } + ConstructorDecl* _getDefaultCtor(StructDecl* structDecl) { for (auto ctor : structDecl->getMembersOfType()) { - // 1. default ctor must have definition - // 2. default ctor must have no parameters or all parameters have init expr - if (!ctor->body || (ctor->members.getCount() != 0 && !allParamHaveInitExpr(ctor))) - continue; - return ctor; + if (_isDefaultCtor(ctor)) + return ctor; } return nullptr; } From 5771007f0f14dad1d69c1d499758d10fa24bc087 Mon Sep 17 00:00:00 2001 From: kaizhangNV Date: Thu, 19 Sep 2024 19:19:12 -0700 Subject: [PATCH 095/100] change function '_doesCtorExpectInitializerListUsage' to '_isSynthisizedMemberwiseCtor' --- source/slang/slang-check-decl.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 098c034637..d381cf4bfc 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -8294,7 +8294,7 @@ namespace Slang return as(stmt->body); } - static bool _doesCtorExpectInitializerListUsage(ConstructorDecl* ctor) + static bool _isSynthisizedMemberwiseCtor(ConstructorDecl* ctor) { return ctor->containsOption(ConstructorTags::Synthesized) && ctor->getParameters().getCount() != 0 @@ -8464,7 +8464,7 @@ namespace Slang // Synthesized constructors should not inject a defaultCtor of base-struct-type // unless ctor has 0 parameters. This is to allow a ctor which desires to be // init-list initialized to control which members initialize. - if(_doesCtorExpectInitializerListUsage(ctor)) + if(_isSynthisizedMemberwiseCtor(ctor)) continue; auto seqStmtChild = m_astBuilder->create(); @@ -8528,7 +8528,7 @@ namespace Slang for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { auto ctor = ctorInfo.m_ctor; - + ThisExpr* thisExpr = m_astBuilder->create(); thisExpr->scope = ctor->ownedScope; thisExpr->type = ctor->returnType.type; @@ -8612,13 +8612,15 @@ namespace Slang for (auto& ctorInfo : structDeclInfo.m_ctorInfoList) { auto ctor = ctorInfo.m_ctor; - if(!_doesCtorExpectInitializerListUsage(ctor)) + + if(!_isSynthisizedMemberwiseCtor(ctor)) continue; + auto ctorVisibility = getDeclVisibility(ctor); Index paramIndex = 0; auto paramList = ctor->getParameters(); - + Index memberIndex = 0; auto members = membersOfStructDeclInstance; @@ -8707,7 +8709,7 @@ namespace Slang continue; } } - + // Part 2 // Regular assignment logic paramIndex++; From d966b3fc88a24a4f45780b651bb918a2c216889c Mon Sep 17 00:00:00 2001 From: kaizhangNV Date: Thu, 19 Sep 2024 19:39:32 -0700 Subject: [PATCH 096/100] replace all 'ZeroInit' to 'DefaultInit' --- source/slang/slang-ast-modifier.h | 4 +- source/slang/slang-check-conversion.cpp | 2 +- source/slang/slang-check-decl.cpp | 82 +++++++++++----------- source/slang/slang-check-impl.h | 8 +-- source/slang/slang-check-overload.cpp | 2 +- source/slang/slang-constructor-utility.cpp | 18 ++--- 6 files changed, 58 insertions(+), 58 deletions(-) diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index d7a46e707d..8d9263bd45 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -38,8 +38,8 @@ class ToBeSynthesizedModifier : public Modifier {SLANG_AST_CLASS(ToBeSynthesized // Marks that the definition of a decl is synthesized. class SynthesizedModifier : public Modifier { SLANG_AST_CLASS(SynthesizedModifier) }; -// Marks that the definition of a decl is our $ZeroInit function. -class ZeroInitModifier : public Modifier { SLANG_AST_CLASS(ZeroInitModifier) }; +// Marks that the definition of a decl is our $DefaultInit function. +class DefaultInitModifier : public Modifier { SLANG_AST_CLASS(DefaultInitModifier) }; // Marks a synthesized variable as local temporary variable. class LocalTempVarModifier : public Modifier { SLANG_AST_CLASS(LocalTempVarModifier) }; diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 44d4cfd830..5a762cb181 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -537,7 +537,7 @@ namespace Slang { if (outToExpr) { - *outToExpr = constructZeroInitListFunc(this, toStructDecl, toType, ConstructZeroInitListOptions::CheckToAvoidRecursion); + *outToExpr = constructDefaultInitListFunc(this, toStructDecl, toType, ConstructDefaultInitListOptions::CheckToAvoidRecursion); (*outToExpr)->loc = fromInitializerListExpr->loc; } return true; diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 7a7552cde8..891d0e4e5b 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2704,49 +2704,49 @@ namespace Slang // // // Steps: - // 1. Generate $ZeroInit + // 1. Generate $DefaultInit // 2. Add an declaration for default-ctor if missing a real default-ctor. // 3. Generate 'member-wise' constructors if (_structHasMemberWithValue(getASTBuilder(), structDecl)) { - // 1. Generate $ZeroInit + // 1. Generate $DefaultInit // - // $ZeroInit is a synthisized static-function only used In 2 cases: + // $DefaultInit is a synthisized static-function only used In 2 cases: // 1. if `{}` is used inside a `__init()` // 2. if `{}` is used and a user has a 'synthisized __init()` // - // Use of $ZeroInit is only for functionality of `{}` to avoid hacks. + // Use of $DefaultInit is only for functionality of `{}` to avoid hacks. { - auto zeroInitFunc = m_astBuilder->create(); - auto ctorName = getName("$ZeroInit"); - zeroInitFunc->ownedScope = m_astBuilder->create(); - zeroInitFunc->ownedScope->containerDecl = zeroInitFunc; - zeroInitFunc->ownedScope->parent = getScope(structDecl); - zeroInitFunc->parentDecl = structDecl; - zeroInitFunc->loc = structDecl->loc; - zeroInitFunc->closingSourceLoc = zeroInitFunc->loc; - zeroInitFunc->nameAndLoc.name = ctorName; - zeroInitFunc->nameAndLoc.loc = zeroInitFunc->loc; - zeroInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); + auto defaultInitFunc = m_astBuilder->create(); + auto ctorName = getName("$DefaultInit"); + defaultInitFunc->ownedScope = m_astBuilder->create(); + defaultInitFunc->ownedScope->containerDecl = defaultInitFunc; + defaultInitFunc->ownedScope->parent = getScope(structDecl); + defaultInitFunc->parentDecl = structDecl; + defaultInitFunc->loc = structDecl->loc; + defaultInitFunc->closingSourceLoc = defaultInitFunc->loc; + defaultInitFunc->nameAndLoc.name = ctorName; + defaultInitFunc->nameAndLoc.loc = defaultInitFunc->loc; + defaultInitFunc->returnType.type = calcThisType(makeDeclRef(structDecl)); auto body = m_astBuilder->create(); body->scopeDecl = m_astBuilder->create(); body->scopeDecl->ownedScope = m_astBuilder->create(); - body->scopeDecl->ownedScope->parent = getScope(zeroInitFunc); - body->scopeDecl->parentDecl = zeroInitFunc; - body->scopeDecl->loc = zeroInitFunc->loc; - body->scopeDecl->closingSourceLoc = zeroInitFunc->loc; - body->closingSourceLoc = zeroInitFunc->closingSourceLoc; - zeroInitFunc->body = body; + body->scopeDecl->ownedScope->parent = getScope(defaultInitFunc); + body->scopeDecl->parentDecl = defaultInitFunc; + body->scopeDecl->loc = defaultInitFunc->loc; + body->scopeDecl->closingSourceLoc = defaultInitFunc->loc; + body->closingSourceLoc = defaultInitFunc->closingSourceLoc; + defaultInitFunc->body = body; body->body = m_astBuilder->create(); - addAutoDiffModifiersToFunc(this, m_astBuilder, zeroInitFunc); - addModifier(zeroInitFunc, m_astBuilder->create()); + addAutoDiffModifiersToFunc(this, m_astBuilder, defaultInitFunc); + addModifier(defaultInitFunc, m_astBuilder->create()); - addModifier(zeroInitFunc, m_astBuilder->create()); - addVisibilityModifier(m_astBuilder, zeroInitFunc, getDeclVisibility(structDecl)); - addModifier(zeroInitFunc, m_astBuilder->create()); - structDecl->addMember(zeroInitFunc); + addModifier(defaultInitFunc, m_astBuilder->create()); + addVisibilityModifier(m_astBuilder, defaultInitFunc, getDeclVisibility(structDecl)); + addModifier(defaultInitFunc, m_astBuilder->create()); + structDecl->addMember(defaultInitFunc); } // 2. Add an declaration for default-ctor if missing a real default-ctor. @@ -9041,21 +9041,21 @@ namespace Slang } } - // Fill in our $ZeroInit - if (auto zeroInitListFunc = findZeroInitListFunc(structDecl)) + // Fill in our $DefaultInit + if (auto defaultInitListFunc = findDefaultInitListFunc(structDecl)) { - SLANG_ASSERT(zeroInitListFunc->getParameters().getCount() == 0); - SLANG_ASSERT(zeroInitListFunc->findModifier()); + SLANG_ASSERT(defaultInitListFunc->getParameters().getCount() == 0); + SLANG_ASSERT(defaultInitListFunc->findModifier()); - SLANG_ASSERT(as(zeroInitListFunc->body)); - auto block = as(zeroInitListFunc->body); + SLANG_ASSERT(as(defaultInitListFunc->body)); + auto block = as(defaultInitListFunc->body); SLANG_ASSERT(as(block->body)); auto seqStmt = as(block->body); /* 3 steps: 1. Assign DefaultConstructExpr to `this` - 2. Insert `super::$ZeroInit()` into `this->$ZeroInit` + 2. Insert `super::$DefaultInit()` into `this->$DefaultInit` 3. Assign initExpr to all members */ @@ -9069,7 +9069,7 @@ namespace Slang addModifier(structVarDecl, m_astBuilder->create()); structVarDecl->type = TypeExp(structDeclType); structVarDecl->initExpr = defaultConstructExpr; - structVarDecl->parentDecl = zeroInitListFunc; + structVarDecl->parentDecl = defaultInitListFunc; structVarDecl->loc = seqStmt->loc; ensureDecl(structVarDecl, DeclCheckState::VarInitExprAreChecked); @@ -9090,7 +9090,7 @@ namespace Slang seqStmt->stmts.add(structAssignExprStmt); // Part 2 - // Insert `super::$ZeroInit()` into `this->$ZeroInit` + // Insert `super::$DefaultInit()` into `this->$DefaultInit` // Only insert if we have values to insert for if (baseStructInfo) { @@ -9098,10 +9098,10 @@ namespace Slang { if (_structHasMemberWithValue(getASTBuilder(), structDecl)) { - Expr* zeroInitFunc = constructZeroInitListFunc(this, baseStructDecl, baseStructInfo->m_inheritanceDecl->base.type, ConstructZeroInitListOptions::PreferZeroInitFunc); + Expr* defaultInitFunc = constructDefaultInitListFunc(this, baseStructDecl, baseStructInfo->m_inheritanceDecl->base.type, ConstructDefaultInitListOptions::PreferDefaultInitFunc); auto assign = m_astBuilder->create(); - assign->left = coerce(CoercionSite::Initializer, zeroInitFunc->type, structVarDeclExpr); - assign->right = zeroInitFunc; + assign->left = coerce(CoercionSite::Initializer, defaultInitFunc->type, structVarDeclExpr); + assign->right = defaultInitFunc; auto stmt = m_astBuilder->create(); stmt->expression = assign; stmt->loc = seqStmt->loc; @@ -9116,7 +9116,7 @@ namespace Slang { auto member = memberRef.getDecl(); - addCudaHostModifierIfRequired(zeroInitListFunc, member, foundCudaHostModifier); + addCudaHostModifierIfRequired(defaultInitListFunc, member, foundCudaHostModifier); auto initExpr = member->initExpr; if (!initExpr) @@ -9125,7 +9125,7 @@ namespace Slang MemberExpr* memberExpr = m_astBuilder->create(); memberExpr->baseExpression = structVarDeclExpr; memberExpr->declRef = member->getDefaultDeclRef(); - memberExpr->scope = zeroInitListFunc->ownedScope; + memberExpr->scope = defaultInitListFunc->ownedScope; memberExpr->loc = member->loc; memberExpr->name = member->getName(); memberExpr->type = GetTypeForDeclRef(member, member->loc); diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index b11873d430..b1a38c9eca 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -3036,14 +3036,14 @@ namespace Slang bool isDefaultInitializable(Type* varDeclType, VarDeclBase* associatedDecl); Expr* constructDefaultInitExprForVar(SemanticsVisitor* visitor, TypeExp varDeclType, VarDeclBase* decl); - enum class ConstructZeroInitListOptions : UInt + enum class ConstructDefaultInitListOptions : UInt { None = 0 << 0, - PreferZeroInitFunc = 1 << 0, + PreferDefaultInitFunc = 1 << 0, CheckToAvoidRecursion = 1 << 2, }; - Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructZeroInitListOptions options); - FuncDecl* findZeroInitListFunc(StructDecl* structDecl); + Expr* constructDefaultInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructDefaultInitListOptions options); + FuncDecl* findDefaultInitListFunc(StructDecl* structDecl); bool isCStyleStructDecl(SemanticsVisitor* visitor, StructDecl* decl, List const& ctorList); diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 96f744bb2f..52f9303117 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -2394,7 +2394,7 @@ namespace Slang /// We allow a special case for when `funcExpr` is expected to be a Default initializer /// but none exist. Note, we cannot just create a default initializer for every variable /// since then we are introducing initialization to every variable through an indirect - /// init returning data. Instead we will call `$ZeroInit` through this logic below. + /// init returning data. Instead we will call `$DefaultInit` through this logic below. Expr* _tryToSpecialCaseOverloadDefaultConstructWithoutInit(SemanticsVisitor* visitor, SemanticsVisitor::OverloadResolveContext& context, Expr* expr, OverloadCandidate* bestCandidate) { if (context.argCount == 0) diff --git a/source/slang/slang-constructor-utility.cpp b/source/slang/slang-constructor-utility.cpp index 39108bdde0..e4ce2a8591 100644 --- a/source/slang/slang-constructor-utility.cpp +++ b/source/slang/slang-constructor-utility.cpp @@ -153,11 +153,11 @@ namespace Slang } } - FuncDecl* findZeroInitListFunc(StructDecl* structDecl) + FuncDecl* findDefaultInitListFunc(StructDecl* structDecl) { for (auto funcDecl : structDecl->getMembersOfType()) { - if (!funcDecl->findModifier()) + if (!funcDecl->findModifier()) continue; return funcDecl; } @@ -172,15 +172,15 @@ namespace Slang invoke->type = structDeclType; return invoke; } - Expr* constructZeroInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructZeroInitListOptions options) + Expr* constructDefaultInitListFunc(SemanticsVisitor* visitor, StructDecl* structDecl, Type* structDeclType, ConstructDefaultInitListOptions options) { SLANG_ASSERT(structDecl); // 1. Prefer non-synth default-ctor - // * Skip this option if `ConstructZeroInitListOptions::PreferZeroInitFunc` is true - // * Skip this option if `ConstructZeroInitListOptions::CheckToAvoidRecursion` detects recursion + // * Skip this option if `ConstructDefaultInitListOptions::PreferDefaultInitFunc` is true + // * Skip this option if `ConstructDefaultInitListOptions::CheckToAvoidRecursion` detects recursion // * Only user-defined ctor will try and have recursion of `{}` - // 2. Prefer $ZeroInit + // 2. Prefer $DefaultInit // 3. Prefer any default-ctor // 4. Use `DefaultConstructExpr` @@ -188,10 +188,10 @@ namespace Slang auto defaultCtor = _getDefaultCtor(structDecl); if(defaultCtor && !defaultCtor->containsOption(ConstructorTags::Synthesized) - && !((UInt)options & (UInt)ConstructZeroInitListOptions::PreferZeroInitFunc)) + && !((UInt)options & (UInt)ConstructDefaultInitListOptions::PreferDefaultInitFunc)) { bool canCreateCtor = true; - if(((UInt)options & (UInt)ConstructZeroInitListOptions::CheckToAvoidRecursion)) + if(((UInt)options & (UInt)ConstructDefaultInitListOptions::CheckToAvoidRecursion)) { auto callingScope = visitor->getOuterScope(); while (callingScope) @@ -209,7 +209,7 @@ namespace Slang } // 2. - if (auto defaultInitFunc = findZeroInitListFunc(structDecl)) + if (auto defaultInitFunc = findDefaultInitListFunc(structDecl)) { auto* invoke = visitor->getASTBuilder()->create(); DeclRef member; From 69cb426a73d67ddfdabcca87da4b49f544fcb507 Mon Sep 17 00:00:00 2001 From: kaizhangNV Date: Fri, 20 Sep 2024 09:52:09 -0700 Subject: [PATCH 097/100] remove the WAR in hlsl.meta.slang --- source/slang/hlsl.meta.slang | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 14df6a0278..58923d838e 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -20189,13 +20189,8 @@ ${ case hlsl: uint isSingleLod = 0; - // Note: we cannot pass `Shape.dimensions` - // directly as a parameter into a Call, otherwise - // AST lookup fails (bug?), creating an intermediary works - // so we do this workaround. - int shapeDim = Shape.dimensions; Footprint footprint = {__queryFootprint$(CoarseOrFine)NVAPI( - shapeDim, + Shape.dimensions, __getRegisterSpace(this), __getRegisterIndex(this), __getRegisterSpace(sampler), __getRegisterIndex(sampler), __vectorReshape<3>(coords), granularity, /* out */isSingleLod), false}; @@ -20227,9 +20222,8 @@ ${ return footprint; case hlsl: uint isSingleLod = 0; - int shapeDim = Shape.dimensions; Footprint footprint = {__queryFootprint$(CoarseOrFine)BiasNVAPI( - shapeDim, + Shape.dimensions, __getRegisterSpace(this), __getRegisterIndex(this), __getRegisterSpace(sampler), __getRegisterIndex(sampler), __vectorReshape<3>(coords), granularity, lodBias, /* out */isSingleLod), false}; @@ -20311,9 +20305,8 @@ ${ return footprint; case hlsl: uint isSingleLod = 0; - int shapeDim = Shape.dimensions; Footprint footprint = {__queryFootprint$(CoarseOrFine)LevelNVAPI( - shapeDim, + Shape.dimensions, __getRegisterSpace(this), __getRegisterIndex(this), __getRegisterSpace(sampler), __getRegisterIndex(sampler), __vectorReshape<3>(coords), granularity, lod, /* out */isSingleLod), false}; @@ -20351,9 +20344,8 @@ ${{{ return footprint; case hlsl: uint isSingleLod = 0; - int shapeDim = Shape.dimensions; Footprint footprint = {__queryFootprint$(CoarseOrFine)GradNVAPI( - shapeDim, + Shape.dimensions, __getRegisterSpace(this), __getRegisterIndex(this), __getRegisterSpace(sampler), __getRegisterIndex(sampler), __vectorReshape<3>(coords), granularity, __vectorReshape<3>(dx), __vectorReshape<3>(dy), /* out */isSingleLod), false}; From 2b6f7a26688b60a74fde979fbfff28a24a493e5c Mon Sep 17 00:00:00 2001 From: kaizhangNV Date: Fri, 20 Sep 2024 12:57:11 -0700 Subject: [PATCH 098/100] Replace the name '_tryToSpecialCaseOverloadDefaultConstructWithoutInit' to '_tryOverloadWithDefaultInit' This function just tried to resolve a problem that struct S {int x}; S s = S(); We will try to overload `S()` with synthesized default initializer. Because there is no such function with signature of "S S()". --- source/slang/slang-check-overload.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 52f9303117..7da1e2d45c 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -2395,7 +2395,9 @@ namespace Slang /// but none exist. Note, we cannot just create a default initializer for every variable /// since then we are introducing initialization to every variable through an indirect /// init returning data. Instead we will call `$DefaultInit` through this logic below. - Expr* _tryToSpecialCaseOverloadDefaultConstructWithoutInit(SemanticsVisitor* visitor, SemanticsVisitor::OverloadResolveContext& context, Expr* expr, OverloadCandidate* bestCandidate) + /// struct S { int x; } + /// S s = S(); // This will call S.$DefaultInit(). + Expr* _tryOverloadWithDefaultInit(SemanticsVisitor* visitor, SemanticsVisitor::OverloadResolveContext& context, Expr* expr, OverloadCandidate* bestCandidate) { if (context.argCount == 0) { @@ -2595,7 +2597,7 @@ namespace Slang } else if (context.bestCandidate) { - if (auto specialCase = _tryToSpecialCaseOverloadDefaultConstructWithoutInit(this, context, expr, context.bestCandidate)) + if (auto specialCase = _tryOverloadWithDefaultInit(this, context, expr, context.bestCandidate)) return specialCase; // There was one best candidate, even if it might not have been From 1861df485cba63b2a6c04d7e79977da912a2f1f8 Mon Sep 17 00:00:00 2001 From: kaizhangNV Date: Mon, 23 Sep 2024 20:47:55 -0700 Subject: [PATCH 099/100] Do not remove the default ctor --- source/slang/slang-check-decl.cpp | 20 ----------------- source/slang/slang-check-overload.cpp | 32 --------------------------- 2 files changed, 52 deletions(-) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 891d0e4e5b..7c7e1101cb 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -9021,26 +9021,6 @@ namespace Slang seqStmt->stmts.insert(ctorInfo.m_insertOffset++, seqStmtChild); } - // Compiler generated ctor may be destroyed - bool destroyedDefaultCtor = false; - if(structDeclInfo.m_defaultCtor - && structDeclInfo.m_defaultCtor->containsOption(ConstructorTags::Synthesized)) - { - if (!structDeclInfo.m_defaultCtor->body) - destroyedDefaultCtor = true; - else if (auto block = as(structDeclInfo.m_defaultCtor->body)) - { - if (as(block->body)->stmts.getCount() == 0) - destroyedDefaultCtor = true; - } - if (destroyedDefaultCtor) - { - structDecl->members.remove(structDeclInfo.m_defaultCtor); - structDecl->invalidateMemberDictionary(); - structDecl->buildMemberDictionary(); - } - } - // Fill in our $DefaultInit if (auto defaultInitListFunc = findDefaultInitListFunc(structDecl)) { diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 7da1e2d45c..13dcb80de8 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -2390,35 +2390,6 @@ namespace Slang return argsListBuilder.produceString(); } - - /// We allow a special case for when `funcExpr` is expected to be a Default initializer - /// but none exist. Note, we cannot just create a default initializer for every variable - /// since then we are introducing initialization to every variable through an indirect - /// init returning data. Instead we will call `$DefaultInit` through this logic below. - /// struct S { int x; } - /// S s = S(); // This will call S.$DefaultInit(). - Expr* _tryOverloadWithDefaultInit(SemanticsVisitor* visitor, SemanticsVisitor::OverloadResolveContext& context, Expr* expr, OverloadCandidate* bestCandidate) - { - if (context.argCount == 0) - { - auto oldMode = context.mode; - context.mode = SemanticsVisitor::OverloadResolveContext::Mode::JustTrying; - bool arityIsValid = visitor->TryCheckOverloadCandidateArity(context, *bestCandidate); - context.mode = oldMode; - - if (!arityIsValid) - { - auto initListExpr = visitor->getASTBuilder()->create(); - initListExpr->loc = expr->loc; - initListExpr->type = visitor->getASTBuilder()->getInitializerListType(); - Expr* outExpr = nullptr; - if (visitor->_coerceInitializerList(bestCandidate->resultType, &outExpr, initListExpr)) - return outExpr; - } - } - return nullptr; - } - Expr* SemanticsVisitor::ResolveInvoke(InvokeExpr * expr) { OverloadResolveContext context; @@ -2597,9 +2568,6 @@ namespace Slang } else if (context.bestCandidate) { - if (auto specialCase = _tryOverloadWithDefaultInit(this, context, expr, context.bestCandidate)) - return specialCase; - // There was one best candidate, even if it might not have been // applicable in the end. // We will report errors for this one candidate, then, to give From fde91412698b41aa9594675a63e5361f35d3b841 Mon Sep 17 00:00:00 2001 From: kaizhangNV Date: Mon, 23 Sep 2024 22:01:58 -0700 Subject: [PATCH 100/100] DNS: Modify all the tests that does not have empty initializer This commit will be reverted when the initializer list re-work is done. This is just to unblock the test failure when we're in the middle ground. --- tests/autodiff/cuda-kernel-export.slang | 4 +-- tests/autodiff/generic-autodiff-1.slang | 2 +- .../material/DiffuseMaterialInstance.slang | 2 +- .../material/GlossyMaterialInstance.slang | 2 +- tests/autodiff/modify-vector-param.slang | 2 +- tests/autodiff/reverse-while-loop-2.slang | 2 +- tests/autodiff/reverse-while-loop-3.slang | 4 +-- tests/bindings/nested-parameter-block-2.slang | 2 +- tests/bindings/nested-parameter-block-3.slang | 2 +- tests/bugs/gh-3845-2.slang | 2 +- tests/bugs/gh-3845.slang | 2 +- tests/bugs/optional.slang | 2 +- .../bugs/specialize-function-array-args.slang | 4 +-- tests/bugs/stk-chk.slang | 4 +-- tests/compute/assoctype-complex.slang | 4 +-- tests/compute/buffer-layout.slang | 10 +++---- tests/compute/cbuffer-legalize.slang | 2 +- tests/compute/dynamic-dispatch-1.slang | 2 +- tests/compute/dynamic-dispatch-10.slang | 2 +- tests/compute/dynamic-dispatch-14.slang | 8 +++--- tests/compute/dynamic-dispatch-16.slang | 8 +++--- tests/compute/dynamic-dispatch-17.slang | 8 +++--- tests/compute/dynamic-dispatch-18.slang | 4 +-- tests/compute/dynamic-dispatch-2.slang | 4 +-- tests/compute/dynamic-dispatch-3.slang | 4 +-- tests/compute/dynamic-dispatch-5.slang | 2 +- tests/compute/dynamic-dispatch-8.slang | 2 +- tests/compute/dynamic-dispatch-9.slang | 2 +- tests/compute/explicit-this-expr.slang | 4 +-- tests/compute/extension-multi-interface.slang | 4 +-- .../generic-interface-method-simple.slang | 4 +-- tests/compute/generic-interface-method.slang | 26 ++++++++++--------- tests/compute/generics-constrained.slang | 4 +-- tests/compute/half-structured-buffer.slang | 8 +++--- tests/compute/implicit-generic-app.slang | 4 +-- tests/compute/implicit-this-expr.slang | 4 +-- .../compute/interface-assoc-type-param.slang | 4 +-- tests/compute/mutating-methods.slang | 2 +- tests/compute/pack-any-value-16bit.slang | 14 +++++----- tests/compute/pointer-emit.slang | 6 ++--- tests/compute/scope-operator.slang | 6 ++--- tests/compute/struct-make.slang | 2 +- .../texture-sample-grad-offset-clamp.slang | 14 +++++----- tests/compute/texture-sampling.slang | 14 +++++----- tests/diagnostics/deprecation.slang | 2 +- tests/front-end/struct.slang | 6 ++--- tests/glsl-intrinsic/intrinsic-texture.slang | 2 +- tests/hlsl-intrinsic/size-of/align-of.slang | 8 +++--- tests/hlsl-intrinsic/size-of/size-of.slang | 8 +++--- .../generics/generic-interface-1.slang | 2 +- tests/language-feature/generics/where-4.slang | 2 +- tests/language-feature/ifunc/functor.slang | 2 +- .../cstyle-init-list-2.slang | 4 +-- .../synth-constructor-private.slang | 6 ++--- .../synth-constructor-public.slang | 6 ++--- .../initializer-lists/user-constructor.slang | 6 ++--- tests/language-feature/struct-in-func.slang | 4 +-- .../swizzles/matrix-swizzle-write-array.slang | 2 +- tests/language-feature/types/optional.slang | 2 +- tests/legalization/vec1.slang | 6 ++--- tests/spirv/array-uniform-param.slang | 4 +-- tests/spirv/bit-field.slang | 2 +- tests/spirv/debug-info.slang | 4 +-- tests/spirv/debug-type-pointer.slang | 6 ++--- tests/spirv/debug-value-dynamic-index.slang | 6 ++--- tests/spirv/large-struct-pack.slang | 2 +- tests/spirv/mutating-method-syn.slang | 2 +- .../unit-test-decl-tree-reflection.cpp | 12 ++++----- 68 files changed, 163 insertions(+), 161 deletions(-) diff --git a/tests/autodiff/cuda-kernel-export.slang b/tests/autodiff/cuda-kernel-export.slang index 39815ede85..f454113219 100644 --- a/tests/autodiff/cuda-kernel-export.slang +++ b/tests/autodiff/cuda-kernel-export.slang @@ -10,8 +10,8 @@ struct MySubType struct MyType { - float2 v; - MySubType sub[2]; + float2 v = {}; + MySubType sub[2] = {}; } struct MyInput diff --git a/tests/autodiff/generic-autodiff-1.slang b/tests/autodiff/generic-autodiff-1.slang index 9ab0d5fef1..be5fc99bf4 100644 --- a/tests/autodiff/generic-autodiff-1.slang +++ b/tests/autodiff/generic-autodiff-1.slang @@ -15,7 +15,7 @@ interface IInterface struct A : IInterface { - float z; + float z = {}; [mutating] float sample() { z = z + 1.0; return 1.0; } }; diff --git a/tests/autodiff/material/DiffuseMaterialInstance.slang b/tests/autodiff/material/DiffuseMaterialInstance.slang index c6f0e315b3..3a3401b69d 100644 --- a/tests/autodiff/material/DiffuseMaterialInstance.slang +++ b/tests/autodiff/material/DiffuseMaterialInstance.slang @@ -5,7 +5,7 @@ __exported import IBSDF; public struct DiffuseBSDF : IBSDF { - public float3 albedo; + public float3 albedo = {}; [TreatAsDifferentiable] public float3 eval(const float3 wiLocal, const float3 woLocal) diff --git a/tests/autodiff/material/GlossyMaterialInstance.slang b/tests/autodiff/material/GlossyMaterialInstance.slang index fb1ce55c0a..4e0a0f0bde 100644 --- a/tests/autodiff/material/GlossyMaterialInstance.slang +++ b/tests/autodiff/material/GlossyMaterialInstance.slang @@ -5,7 +5,7 @@ __exported import IBSDF; public struct GlossyBSDF : IBSDF { - public float3 albedo; + public float3 albedo = {}; public float3 getAlbedo() { diff --git a/tests/autodiff/modify-vector-param.slang b/tests/autodiff/modify-vector-param.slang index d6ddd73868..2084f00647 100644 --- a/tests/autodiff/modify-vector-param.slang +++ b/tests/autodiff/modify-vector-param.slang @@ -8,7 +8,7 @@ typedef float.Differential dfloat; struct Params { - float vv; + float vv = {}; } [Differentiable] diff --git a/tests/autodiff/reverse-while-loop-2.slang b/tests/autodiff/reverse-while-loop-2.slang index 9ad9ac466b..ffcb6c83a1 100644 --- a/tests/autodiff/reverse-while-loop-2.slang +++ b/tests/autodiff/reverse-while-loop-2.slang @@ -10,7 +10,7 @@ typedef float.Differential dfloat; struct P { - bool terminated; + bool terminated = {}; bool isTerminated() { return terminated; } bool isHit() { return !terminated; } } diff --git a/tests/autodiff/reverse-while-loop-3.slang b/tests/autodiff/reverse-while-loop-3.slang index 0a27437e97..d00e9bda94 100644 --- a/tests/autodiff/reverse-while-loop-3.slang +++ b/tests/autodiff/reverse-while-loop-3.slang @@ -14,7 +14,7 @@ typedef float.Differential dfloat; struct P { - bool terminated; + bool terminated = {}; bool isTerminated() { return terminated; } bool isHit() { return !terminated; } }; @@ -25,7 +25,7 @@ struct Data { this.t = dataIn; } - float t; + float t = {}; }; void updateData(Data data) diff --git a/tests/bindings/nested-parameter-block-2.slang b/tests/bindings/nested-parameter-block-2.slang index 790e3d060a..1107739126 100644 --- a/tests/bindings/nested-parameter-block-2.slang +++ b/tests/bindings/nested-parameter-block-2.slang @@ -6,7 +6,7 @@ struct CB { - uint4 value; + uint4 value = {}; } struct MaterialSystem diff --git a/tests/bindings/nested-parameter-block-3.slang b/tests/bindings/nested-parameter-block-3.slang index a9cfcfdaab..3fd07960fd 100644 --- a/tests/bindings/nested-parameter-block-3.slang +++ b/tests/bindings/nested-parameter-block-3.slang @@ -11,7 +11,7 @@ struct CB { - uint4 value; + uint4 value = {}; } struct MaterialSystem diff --git a/tests/bugs/gh-3845-2.slang b/tests/bugs/gh-3845-2.slang index 06a3d1c999..6073ffdad2 100644 --- a/tests/bugs/gh-3845-2.slang +++ b/tests/bugs/gh-3845-2.slang @@ -1,7 +1,7 @@ //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-shaderobj -output-using-type //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-shaderobj -vk -output-using-type -struct Foo {float v;}; +struct Foo {float v = {};}; namespace foo { typedef ::Foo Foo; // unexpected '::', expected identifier; works in dxc/hlsl diff --git a/tests/bugs/gh-3845.slang b/tests/bugs/gh-3845.slang index fe8da5acf9..858a8bfbed 100644 --- a/tests/bugs/gh-3845.slang +++ b/tests/bugs/gh-3845.slang @@ -2,7 +2,7 @@ //TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-shaderobj -vk -output-using-type -struct Foo {float v;}; +struct Foo {float v = {};}; namespace foo { typedef Foo Foo; // cyclic reference 'Foo'; allowed in dxc/hlsl diff --git a/tests/bugs/optional.slang b/tests/bugs/optional.slang index 7a220b23d5..14932d8f25 100644 --- a/tests/bugs/optional.slang +++ b/tests/bugs/optional.slang @@ -6,7 +6,7 @@ interface IFoo void foo(); } -struct S : IFoo { int x; void foo(); } +struct S : IFoo { int x = {}; void foo(); } struct P { diff --git a/tests/bugs/specialize-function-array-args.slang b/tests/bugs/specialize-function-array-args.slang index 8a572eda4c..b1f1f13c2d 100644 --- a/tests/bugs/specialize-function-array-args.slang +++ b/tests/bugs/specialize-function-array-args.slang @@ -13,7 +13,7 @@ struct Params { RWStructuredBuffer buffer; - int a[2]; + int a[2] = {}; }; //TEST_INPUT:ubuffer(data=[9 9 9 9], stride=4):out,name=outputBuffer @@ -38,4 +38,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) int tid = int(dispatchThreadID.x); outputBuffer[tid] = doSomething(params, tid); -} \ No newline at end of file +} diff --git a/tests/bugs/stk-chk.slang b/tests/bugs/stk-chk.slang index c745ecc72a..165e4b0972 100644 --- a/tests/bugs/stk-chk.slang +++ b/tests/bugs/stk-chk.slang @@ -5,7 +5,7 @@ struct LargeStruct { - int values[4096]; + int values[4096] = {}; }; //TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer @@ -52,4 +52,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) int index = int(dispatchThreadID.x); outputBuffer[index] = _calc1(index) + 1; -} \ No newline at end of file +} diff --git a/tests/compute/assoctype-complex.slang b/tests/compute/assoctype-complex.slang index bd53be4857..7fc43735da 100644 --- a/tests/compute/assoctype-complex.slang +++ b/tests/compute/assoctype-complex.slang @@ -18,7 +18,7 @@ interface ISimple struct Val : IBase { typedef int V; - int base; + int base = {}; V sub(V a0, V a1) { return a0 - a1 + base; @@ -49,4 +49,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) v1.base = 2; int outVal = test(s, v0, v1); // == 4.0 outputBuffer[dispatchThreadID.x] = outVal; -} \ No newline at end of file +} diff --git a/tests/compute/buffer-layout.slang b/tests/compute/buffer-layout.slang index a456fa1428..5ba4b9f456 100644 --- a/tests/compute/buffer-layout.slang +++ b/tests/compute/buffer-layout.slang @@ -14,8 +14,8 @@ RWStructuredBuffer outputBuffer; struct A { - float x; - float y; + float x = {}; + float y = {}; } struct S @@ -29,7 +29,7 @@ struct S // // 0 4 4 // - float z; + float z = {}; // The `std140` and D3D constant buffer ruless both // ensure a minimum of 16-byte alignment on `struct` @@ -62,7 +62,7 @@ struct S // struct 12 4 4 // std430 12 4 4 // - int b; + int b = {}; // As our next stress-test case, we will insert an // array with elements that aren't a multiple of @@ -89,7 +89,7 @@ struct S // struct 16 16 4 // std430 16 16 8 // - float2 c[2]; + float2 c[2] = {}; // Now we put in one more ordinary `int` field // just to probe the offset computed so far. diff --git a/tests/compute/cbuffer-legalize.slang b/tests/compute/cbuffer-legalize.slang index d0c0a87774..b892a74b9b 100644 --- a/tests/compute/cbuffer-legalize.slang +++ b/tests/compute/cbuffer-legalize.slang @@ -8,7 +8,7 @@ struct P { - uint4 c; + uint4 c = {}; Texture2D t; SamplerState s; }; diff --git a/tests/compute/dynamic-dispatch-1.slang b/tests/compute/dynamic-dispatch-1.slang index 10d3552ab8..57ee654656 100644 --- a/tests/compute/dynamic-dispatch-1.slang +++ b/tests/compute/dynamic-dispatch-1.slang @@ -18,7 +18,7 @@ int GenericCompute(T obj, int inVal) struct Impl : IInterface { - int base; + int base = {}; int Compute(int inVal) { return base + inVal * inVal; } }; diff --git a/tests/compute/dynamic-dispatch-10.slang b/tests/compute/dynamic-dispatch-10.slang index ddd51c4b92..62230a1c5d 100644 --- a/tests/compute/dynamic-dispatch-10.slang +++ b/tests/compute/dynamic-dispatch-10.slang @@ -25,7 +25,7 @@ int GenericCompute1(T obj, IInterface obj2, int inVal) struct Impl : IInterface { - int base; + int base = {}; int Compute(int inVal) { return base + inVal * inVal; } }; diff --git a/tests/compute/dynamic-dispatch-14.slang b/tests/compute/dynamic-dispatch-14.slang index 641fe938c8..f19a7efa48 100644 --- a/tests/compute/dynamic-dispatch-14.slang +++ b/tests/compute/dynamic-dispatch-14.slang @@ -47,10 +47,10 @@ void computeMain(int3 dispatchThreadID : SV_DispatchThreadID) // Type must be marked `public` to ensure it is visible in the generated DLL. export struct MyImpl : IInterface { - int val; + int val = {}; export struct TAssoc : IAssoc { - int val; + int val = {}; int eval() { return val; } } TAssoc run(int input) @@ -63,10 +63,10 @@ export struct MyImpl : IInterface export struct MyImpl2 : IInterface { - int val; + int val = {}; export struct TAssoc : IAssoc { - int val; + int val = {}; int eval() { return val; } } TAssoc run(int input) diff --git a/tests/compute/dynamic-dispatch-16.slang b/tests/compute/dynamic-dispatch-16.slang index b9fecb9664..9ce00a3d7c 100644 --- a/tests/compute/dynamic-dispatch-16.slang +++ b/tests/compute/dynamic-dispatch-16.slang @@ -12,8 +12,8 @@ interface IInterface struct UserDefinedPackedType { - float3 val; - uint flags; + float3 val = {}; + uint flags = {}; }; //TEST_INPUT:ubuffer(data=[0], stride=4):out,name=gOutputBuffer @@ -40,14 +40,14 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) struct FloatVal : IInterface { - float val; + float val = {}; float run() { return val; } }; interface ISomething{void g();} -struct Float4Struct : ISomething { float4 val; void g() {} } +struct Float4Struct : ISomething { float4 val = {}; void g() {} } struct Float4Val : IInterface { Float4Struct val; diff --git a/tests/compute/dynamic-dispatch-17.slang b/tests/compute/dynamic-dispatch-17.slang index e89482a5b7..ab99de2f23 100644 --- a/tests/compute/dynamic-dispatch-17.slang +++ b/tests/compute/dynamic-dispatch-17.slang @@ -17,8 +17,8 @@ interface IInterface struct UserDefinedPackedType { - float3 val; - uint flags; + float3 val = {}; + uint flags = {}; }; //TEST_INPUT:ubuffer(data=[0], stride=4):out,name=gOutputBuffer @@ -49,14 +49,14 @@ struct ReturnsZero : IReturnsZero } struct FloatVal : IInterface { - float val; + float val = {}; float run() { Z z = Z(); return val + z.get(); } }; -struct Float4Struct { float4 val; } +struct Float4Struct { float4 val = {}; } struct Float4Val : IInterface { Float4Struct val; diff --git a/tests/compute/dynamic-dispatch-18.slang b/tests/compute/dynamic-dispatch-18.slang index 23cdabbbdc..79dedc82f5 100644 --- a/tests/compute/dynamic-dispatch-18.slang +++ b/tests/compute/dynamic-dispatch-18.slang @@ -19,10 +19,10 @@ interface IInterface struct Impl : IInterface { - int data; + int data = {}; struct Getter : IReturnsZero { - bool data; + bool data = {}; float get() { if (data) return 0.0; else return 1.0;} } Getter createGetter() { Getter g; g.data = true; return g; } diff --git a/tests/compute/dynamic-dispatch-2.slang b/tests/compute/dynamic-dispatch-2.slang index 06aed6e71c..ec306c9bea 100644 --- a/tests/compute/dynamic-dispatch-2.slang +++ b/tests/compute/dynamic-dispatch-2.slang @@ -29,11 +29,11 @@ struct Impl : IInterface { struct Assoc : IAssoc { - int val; + int val = {}; int get() { return val; } static int getBase() { return -1; } }; - int base; + int base = {}; int Compute(int inVal) { return base + inVal * inVal; } }; diff --git a/tests/compute/dynamic-dispatch-3.slang b/tests/compute/dynamic-dispatch-3.slang index 94430e638a..21f52aa15b 100644 --- a/tests/compute/dynamic-dispatch-3.slang +++ b/tests/compute/dynamic-dispatch-3.slang @@ -38,11 +38,11 @@ struct Impl : IInterface { struct Assoc : IAssoc { - int val; + int val = {}; int get() { return val; } static int getBase(T t) { return t.getVal(); } }; - int base; + int base = {}; int Compute(int inVal) { return base + inVal * inVal; } }; diff --git a/tests/compute/dynamic-dispatch-5.slang b/tests/compute/dynamic-dispatch-5.slang index 61d4024af5..dbe462323e 100644 --- a/tests/compute/dynamic-dispatch-5.slang +++ b/tests/compute/dynamic-dispatch-5.slang @@ -17,7 +17,7 @@ int GenericCompute(int inVal, T obj, T other) struct Impl : IInterface { - int base; + int base = {}; int Compute(int inVal, This other) { return other.base + base + inVal; } }; int test(int inVal) diff --git a/tests/compute/dynamic-dispatch-8.slang b/tests/compute/dynamic-dispatch-8.slang index 62d3f0a9d4..d5a9cfc8ed 100644 --- a/tests/compute/dynamic-dispatch-8.slang +++ b/tests/compute/dynamic-dispatch-8.slang @@ -18,7 +18,7 @@ int GenericCompute(IInterface obj, int inVal) struct Impl : IInterface { - int base; + int base = {}; int Compute(int inVal) { return base + inVal * inVal; } }; diff --git a/tests/compute/dynamic-dispatch-9.slang b/tests/compute/dynamic-dispatch-9.slang index 77112a318b..0672181076 100644 --- a/tests/compute/dynamic-dispatch-9.slang +++ b/tests/compute/dynamic-dispatch-9.slang @@ -28,7 +28,7 @@ int GenericCompute1(T obj, int inVal) struct Impl : IInterface { - int base; + int base = {}; int Compute(int inVal) { return base + inVal * inVal; } }; diff --git a/tests/compute/explicit-this-expr.slang b/tests/compute/explicit-this-expr.slang index baf718be0d..d73584a246 100644 --- a/tests/compute/explicit-this-expr.slang +++ b/tests/compute/explicit-this-expr.slang @@ -7,7 +7,7 @@ struct A { - float x; + float x = {}; float addWith(float y) { @@ -33,4 +33,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) float inVal = float(tid); float outVal = test(inVal); outputBuffer[tid] = outVal; -} \ No newline at end of file +} diff --git a/tests/compute/extension-multi-interface.slang b/tests/compute/extension-multi-interface.slang index 23c9174110..94dc168fab 100644 --- a/tests/compute/extension-multi-interface.slang +++ b/tests/compute/extension-multi-interface.slang @@ -22,7 +22,7 @@ interface IAddAndSub struct Simple : IAdd { - float base; + float base = {}; float addf(float u, float v) { return u+v; @@ -49,4 +49,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) s.base = 0.0; float outVal = testAddSub(s); outputBuffer[dispatchThreadID.x] = outVal; -} \ No newline at end of file +} diff --git a/tests/compute/generic-interface-method-simple.slang b/tests/compute/generic-interface-method-simple.slang index 0e20947d16..dd8d265427 100644 --- a/tests/compute/generic-interface-method-simple.slang +++ b/tests/compute/generic-interface-method-simple.slang @@ -22,7 +22,7 @@ struct StandardVertexInterpolant : IVertexInterpolant struct MaterialPattern1 : IBRDFPattern { - float base; + float base = {}; __generic float evalPattern(TVertexInterpolant interpolants) { @@ -46,4 +46,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) mp1.base = 0.5; float outVal = test(mp1, vertInterp); outputBuffer[dispatchThreadID.x] = outVal; -} \ No newline at end of file +} diff --git a/tests/compute/generic-interface-method.slang b/tests/compute/generic-interface-method.slang index fade14d412..56d12141a0 100644 --- a/tests/compute/generic-interface-method.slang +++ b/tests/compute/generic-interface-method.slang @@ -6,25 +6,27 @@ RWStructuredBuffer outputBuffer; struct DisneyBRDFPattern { - float3 baseColor; - float3 normal; - float specular, metallic, roughness; - float opacity; - float3 emmissive; - float ambientOcclusion; + float3 baseColor = {}; + float3 normal = {}; + float specular = {}; + float metallic = {}; + float roughness = {}; + float opacity = {}; + float3 emmissive = {}; + float ambientOcclusion = {}; }; struct VertexPosition { - float3 pos; - float3 normal; - float2 uv; + float3 pos = {}; + float3 normal = {}; + float2 uv = {}; }; struct CameraView { - float3 camPos; - float3 camDir; + float3 camPos = {}; + float3 camDir = {}; }; interface IVertexInterpolant @@ -84,4 +86,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) MaterialPattern1 mp1; float outVal = test(vertInterp, mp1); outputBuffer[dispatchThreadID.x] = outVal; -} \ No newline at end of file +} diff --git a/tests/compute/generics-constrained.slang b/tests/compute/generics-constrained.slang index 435b840d1f..d166c18bce 100644 --- a/tests/compute/generics-constrained.slang +++ b/tests/compute/generics-constrained.slang @@ -10,7 +10,7 @@ interface Helper struct A : Helper { - float a; + float a = {}; float getHelp() { @@ -42,4 +42,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) float outVal = testHelp(a); outputBuffer[tid] = outVal; -} \ No newline at end of file +} diff --git a/tests/compute/half-structured-buffer.slang b/tests/compute/half-structured-buffer.slang index 973e84e7b1..7329f17e13 100644 --- a/tests/compute/half-structured-buffer.slang +++ b/tests/compute/half-structured-buffer.slang @@ -6,9 +6,9 @@ struct Thing { - uint pos; - float radius; - half4 color; + uint pos = {}; + float radius = {}; + half4 color = {}; }; //TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=16):out,name outputBuffer @@ -29,4 +29,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) thing.radius = v; outputBuffer[tid] = thing; -} \ No newline at end of file +} diff --git a/tests/compute/implicit-generic-app.slang b/tests/compute/implicit-generic-app.slang index c41b5e31d8..460e1b02bf 100644 --- a/tests/compute/implicit-generic-app.slang +++ b/tests/compute/implicit-generic-app.slang @@ -12,7 +12,7 @@ interface ISimple struct Simple : ISimple { - int val; + int val = {}; int getVal() { return val; } }; @@ -38,4 +38,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) int tid = (int) dispatchThreadID.x; int outVal = test(tid); outputBuffer[tid] = outVal; -} \ No newline at end of file +} diff --git a/tests/compute/implicit-this-expr.slang b/tests/compute/implicit-this-expr.slang index e8b7200938..1cd7711c33 100644 --- a/tests/compute/implicit-this-expr.slang +++ b/tests/compute/implicit-this-expr.slang @@ -6,7 +6,7 @@ struct A { - float x; + float x = {}; float addWith(float y) { @@ -31,4 +31,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) float inVal = float(tid); float outVal = test(inVal); outputBuffer[tid] = outVal; -} \ No newline at end of file +} diff --git a/tests/compute/interface-assoc-type-param.slang b/tests/compute/interface-assoc-type-param.slang index a234d457f0..acdc38a98a 100644 --- a/tests/compute/interface-assoc-type-param.slang +++ b/tests/compute/interface-assoc-type-param.slang @@ -18,10 +18,10 @@ interface IEval export struct Impl : IInterface { - uint val; + uint val = {}; struct TEval : IEval { - uint val; + uint val = {}; uint eval() { return val; diff --git a/tests/compute/mutating-methods.slang b/tests/compute/mutating-methods.slang index 6f561e9a66..7f5e23043e 100644 --- a/tests/compute/mutating-methods.slang +++ b/tests/compute/mutating-methods.slang @@ -11,7 +11,7 @@ interface IAccumulator struct Accumulator : IAccumulator { - int state; + int state = {}; [mutating] void accumulate(int v) { diff --git a/tests/compute/pack-any-value-16bit.slang b/tests/compute/pack-any-value-16bit.slang index 07ad0590e0..ff01c68029 100644 --- a/tests/compute/pack-any-value-16bit.slang +++ b/tests/compute/pack-any-value-16bit.slang @@ -12,12 +12,12 @@ interface IInterface struct Val : IInterface { - int16_t v0; - float f0; - uint16_t v1; - float16_t v2; - half v3; - uint16_t v4; + int16_t v0 = {}; + float f0 = {}; + uint16_t v1 = {}; + float16_t v2 = {}; + half v3 = {}; + uint16_t v4 = {}; float run() { return v0 + f0 + v1 + v2 + v3 + v4; @@ -26,7 +26,7 @@ struct Val : IInterface struct UserDefinedPackedType { - uint4 values[2]; + uint4 values[2] = {}; }; //TEST_INPUT:ubuffer(data=[0 0 0], stride=4):out,name=gOutputBuffer diff --git a/tests/compute/pointer-emit.slang b/tests/compute/pointer-emit.slang index 0516e2dfa1..3d72c9a660 100644 --- a/tests/compute/pointer-emit.slang +++ b/tests/compute/pointer-emit.slang @@ -4,13 +4,13 @@ struct Something { - int4 field0; - int field1; + int4 field0 = {}; + int field1 = {}; }; struct ArrayType { - Something data[2]; + Something data[2] = {}; }; ArrayType getArray() diff --git a/tests/compute/scope-operator.slang b/tests/compute/scope-operator.slang index 0622adc4a2..2d90702a36 100644 --- a/tests/compute/scope-operator.slang +++ b/tests/compute/scope-operator.slang @@ -17,10 +17,10 @@ enum Color struct Thing { - int a; + int a = {}; struct Another { - int b; + int b = {}; } }; @@ -75,4 +75,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) val = test(val); outputBuffer[tid] = val; -} \ No newline at end of file +} diff --git a/tests/compute/struct-make.slang b/tests/compute/struct-make.slang index b7adf4e838..e5340d596d 100644 --- a/tests/compute/struct-make.slang +++ b/tests/compute/struct-make.slang @@ -7,7 +7,7 @@ struct Thing { - int a; + int a = {}; static Thing make(int v) { Thing thing; diff --git a/tests/compute/texture-sample-grad-offset-clamp.slang b/tests/compute/texture-sample-grad-offset-clamp.slang index b83cc12647..0cee3fedd7 100644 --- a/tests/compute/texture-sample-grad-offset-clamp.slang +++ b/tests/compute/texture-sample-grad-offset-clamp.slang @@ -16,20 +16,20 @@ cbuffer Uniforms struct AssembledVertex { - float3 position; - float3 color; - float2 uv; + float3 position = {}; + float3 color = {}; + float2 uv = {}; }; struct CoarseVertex { - float3 color; - float2 uv; + float3 color = {}; + float2 uv = {}; }; struct Fragment { - float4 color; + float4 color = {}; }; @@ -43,7 +43,7 @@ struct VertexStageInput struct VertexStageOutput { CoarseVertex coarseVertex : CoarseVertex; - float4 sv_position : SV_Position; + float4 sv_position : SV_Position = {}; }; VertexStageOutput vertexMain(VertexStageInput input) diff --git a/tests/compute/texture-sampling.slang b/tests/compute/texture-sampling.slang index 0e319680a3..30c9b45682 100644 --- a/tests/compute/texture-sampling.slang +++ b/tests/compute/texture-sampling.slang @@ -30,20 +30,20 @@ cbuffer Uniforms struct AssembledVertex { - float3 position; - float3 color; - float2 uv; + float3 position = {}; + float3 color = {}; + float2 uv = {}; }; struct CoarseVertex { - float3 color; - float2 uv; + float3 color = {}; + float2 uv = {}; }; struct Fragment { - float4 color; + float4 color = {}; }; @@ -57,7 +57,7 @@ struct VertexStageInput struct VertexStageOutput { CoarseVertex coarseVertex : CoarseVertex; - float4 sv_position : SV_Position; + float4 sv_position : SV_Position = {}; }; VertexStageOutput vertexMain(VertexStageInput input) diff --git a/tests/diagnostics/deprecation.slang b/tests/diagnostics/deprecation.slang index 75dfd51d80..7fad5c8fe1 100644 --- a/tests/diagnostics/deprecation.slang +++ b/tests/diagnostics/deprecation.slang @@ -20,7 +20,7 @@ const int pi = 3; struct Billiards { [deprecated("puns")] - bool bs[22]; + bool bs[22] = {}; } int main() diff --git a/tests/front-end/struct.slang b/tests/front-end/struct.slang index 16b1bebc7f..075b39cb1a 100644 --- a/tests/front-end/struct.slang +++ b/tests/front-end/struct.slang @@ -7,8 +7,8 @@ // struct declaration struct Foo { - float3 a; - float3 b; + float3 a = {}; + float3 b = {}; }; // function on a struct @@ -46,4 +46,4 @@ template shader Test() out @Fragment vec4 colorTarget = vec4(result,1); } -*/ \ No newline at end of file +*/ diff --git a/tests/glsl-intrinsic/intrinsic-texture.slang b/tests/glsl-intrinsic/intrinsic-texture.slang index c40390c57c..e7ee87b59f 100644 --- a/tests/glsl-intrinsic/intrinsic-texture.slang +++ b/tests/glsl-intrinsic/intrinsic-texture.slang @@ -16,7 +16,7 @@ //TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer buffer MyBlockName { - int result; + int result = 0; } outputBuffer; // float diff --git a/tests/hlsl-intrinsic/size-of/align-of.slang b/tests/hlsl-intrinsic/size-of/align-of.slang index c5be345c8c..61b9cbfffb 100644 --- a/tests/hlsl-intrinsic/size-of/align-of.slang +++ b/tests/hlsl-intrinsic/size-of/align-of.slang @@ -15,14 +15,14 @@ enum Enum : int8_t struct Hey { - double b; - Enum e; + double b = {}; + Enum e = {}; }; struct Thing : Hey { - int a; - float b; + int a = {}; + float b = {}; }; [numthreads(4, 1, 1)] diff --git a/tests/hlsl-intrinsic/size-of/size-of.slang b/tests/hlsl-intrinsic/size-of/size-of.slang index fc531bc4ef..f6db0e1a52 100644 --- a/tests/hlsl-intrinsic/size-of/size-of.slang +++ b/tests/hlsl-intrinsic/size-of/size-of.slang @@ -15,14 +15,14 @@ enum Enum : int8_t struct Hey { - double b; - Enum e; + double b = {}; + Enum e = {}; }; struct Thing : Hey { - int a; - float b; + int a = {}; + float b = {}; }; [numthreads(4, 1, 1)] diff --git a/tests/language-feature/generics/generic-interface-1.slang b/tests/language-feature/generics/generic-interface-1.slang index 217e7f06f6..b51c4320f2 100644 --- a/tests/language-feature/generics/generic-interface-1.slang +++ b/tests/language-feature/generics/generic-interface-1.slang @@ -13,7 +13,7 @@ bool test(IEqlTestable v0, T v1) struct MyType : IEqlTestable { - int val; + int val = 0; bool testEql(MyType v1) { return val == v1.val; diff --git a/tests/language-feature/generics/where-4.slang b/tests/language-feature/generics/where-4.slang index 9f86ca7dc8..0e6523d59c 100644 --- a/tests/language-feature/generics/where-4.slang +++ b/tests/language-feature/generics/where-4.slang @@ -19,7 +19,7 @@ interface IFoo struct BarImpl : IBar { typealias TB = int; - int x; + int x = 0; int get() { return x; } } diff --git a/tests/language-feature/ifunc/functor.slang b/tests/language-feature/ifunc/functor.slang index 73987cbbf2..dc2661704f 100644 --- a/tests/language-feature/ifunc/functor.slang +++ b/tests/language-feature/ifunc/functor.slang @@ -5,7 +5,7 @@ struct Functor : IMutatingFunc { - int context; + int context = 0; [mutating] float operator()(float p) diff --git a/tests/language-feature/initializer-lists/cstyle-init-list-2.slang b/tests/language-feature/initializer-lists/cstyle-init-list-2.slang index 2c840f4667..a5554299ae 100644 --- a/tests/language-feature/initializer-lists/cstyle-init-list-2.slang +++ b/tests/language-feature/initializer-lists/cstyle-init-list-2.slang @@ -4,7 +4,7 @@ struct TestInner { - float4 a; + float4 a = {}; }; TestInner makeTestInner(float v) @@ -38,4 +38,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) && all(test.b == float3(2, 2, 2)) && all(test.c.a == float4(3, 3, 3, 3)) ; -} \ No newline at end of file +} diff --git a/tests/language-feature/initializer-lists/synth-constructor-private.slang b/tests/language-feature/initializer-lists/synth-constructor-private.slang index b28d394ec0..e79114fca5 100644 --- a/tests/language-feature/initializer-lists/synth-constructor-private.slang +++ b/tests/language-feature/initializer-lists/synth-constructor-private.slang @@ -2,8 +2,8 @@ public struct TestNested { - private int val1; - private int val2; + private int val1 = {}; + private int val2 = {}; int getVal1() { @@ -59,4 +59,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) ) ? 1 : 0; // BUF: 1 -} \ No newline at end of file +} diff --git a/tests/language-feature/initializer-lists/synth-constructor-public.slang b/tests/language-feature/initializer-lists/synth-constructor-public.slang index 83735403d9..9e942cf54c 100644 --- a/tests/language-feature/initializer-lists/synth-constructor-public.slang +++ b/tests/language-feature/initializer-lists/synth-constructor-public.slang @@ -2,8 +2,8 @@ public struct TestNested { - public int val1; - public int val2; + public int val1 = {}; + public int val2 = {}; } public struct Test @@ -28,4 +28,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) ) ? 1 : 0; // BUF: 1 -} \ No newline at end of file +} diff --git a/tests/language-feature/initializer-lists/user-constructor.slang b/tests/language-feature/initializer-lists/user-constructor.slang index 63c3def7ae..69074b6874 100644 --- a/tests/language-feature/initializer-lists/user-constructor.slang +++ b/tests/language-feature/initializer-lists/user-constructor.slang @@ -5,8 +5,8 @@ public struct TestNested { - public int val1; - public int val2; + public int val1 = {}; + public int val2 = {}; } public struct Test @@ -72,4 +72,4 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) ) ? 1 : 0; // BUF: 1 -} \ No newline at end of file +} diff --git a/tests/language-feature/struct-in-func.slang b/tests/language-feature/struct-in-func.slang index d3bd046f08..21bdda11b7 100644 --- a/tests/language-feature/struct-in-func.slang +++ b/tests/language-feature/struct-in-func.slang @@ -5,8 +5,8 @@ int test(int r) { struct Val { - int a; - int b; + int a = 0; + int b = 0; } Val a; a.a = 1; diff --git a/tests/language-feature/swizzles/matrix-swizzle-write-array.slang b/tests/language-feature/swizzles/matrix-swizzle-write-array.slang index 616a19b198..907d5f51c1 100644 --- a/tests/language-feature/swizzles/matrix-swizzle-write-array.slang +++ b/tests/language-feature/swizzles/matrix-swizzle-write-array.slang @@ -11,7 +11,7 @@ RWStructuredBuffer outputBuffer; struct MySubscriptable { - float2x2 m; + float2x2 m = {}; __subscript() -> float2x2 { get { return m; } diff --git a/tests/language-feature/types/optional.slang b/tests/language-feature/types/optional.slang index ae1711cd7a..a945f0a624 100644 --- a/tests/language-feature/types/optional.slang +++ b/tests/language-feature/types/optional.slang @@ -18,7 +18,7 @@ interface IFoo //TEST_INPUT: type_conformance Impl1:IFoo = 0 struct Impl1 : IFoo { - int data; + int data = 0; int method() { return data; } } diff --git a/tests/legalization/vec1.slang b/tests/legalization/vec1.slang index f3de085b00..5ec79e0847 100644 --- a/tests/legalization/vec1.slang +++ b/tests/legalization/vec1.slang @@ -15,13 +15,13 @@ RWStructuredBuffer outputBuffer; struct V { // 1-vector of 1-vector - vector, 1> oo; + vector, 1> oo = {}; // 1-vector of n-vector - vector, 1> on; + vector, 1> on = {}; // n-vector of 1-vector - vector, 4> no; + vector, 4> no = {}; }; vector get1Vec(int x) diff --git a/tests/spirv/array-uniform-param.slang b/tests/spirv/array-uniform-param.slang index 235e85bbd0..5379e71161 100644 --- a/tests/spirv/array-uniform-param.slang +++ b/tests/spirv/array-uniform-param.slang @@ -10,12 +10,12 @@ RWStructuredBuffer resultBuffer; struct Data { - uint arr[4]; + uint arr[4] = {}; } struct Data2 { - uint arr[4u]; + uint arr[4u] = {}; } //TEST_INPUT: set Uniforms.d = new Data{{1,2,3,4}}; diff --git a/tests/spirv/bit-field.slang b/tests/spirv/bit-field.slang index 878b4483dc..412ea064a8 100644 --- a/tests/spirv/bit-field.slang +++ b/tests/spirv/bit-field.slang @@ -15,7 +15,7 @@ enum Flag } struct Data { - uint flags; + uint flags = {}; [mutating] void setFlag(Flag g, bool v) { const uint bit = uint(g) << 8; diff --git a/tests/spirv/debug-info.slang b/tests/spirv/debug-info.slang index dc225f8ccb..c12b3d5813 100644 --- a/tests/spirv/debug-info.slang +++ b/tests/spirv/debug-info.slang @@ -2,8 +2,8 @@ struct TestType { - float memberA; - float3 memberB; + float memberA = {}; + float3 memberB = {}; RWStructuredBuffer memberC; float getValue() { diff --git a/tests/spirv/debug-type-pointer.slang b/tests/spirv/debug-type-pointer.slang index fd3248c592..72ad671d5c 100644 --- a/tests/spirv/debug-type-pointer.slang +++ b/tests/spirv/debug-type-pointer.slang @@ -14,18 +14,18 @@ RWStructuredBuffer outputBuffer; struct LinkedNode { - float value; + float value = {}; //SPV: [[TYPE_float:%[1-9][0-9]*]] = OpExtInst %void %{{[0-9]*}} DebugTypeBasic [[STRING_float]] //SPV: [[TYPE_float_ptr:%[1-9][0-9]*]] = OpExtInst %void %{{[0-9]*}} DebugTypePointer [[TYPE_float]] //SPV: DebugTypeMember [[STRING_pValue]] [[TYPE_float_ptr]] - float *pValue; + float *pValue = {}; // "MEMBER_pNext" hasn't been declared yet, but OpExtInstWithForwardRefs requires at least one of these "forward declared ID". //SPV: [[FORWARD_LinkedNode:%[1-9][0-9]*]] = OpExtInstWithForwardRefsKHR %void %{{[0-9]*}} DebugTypeComposite [[STRING_LinkedNode]] {{.*}} [[MEMBER_pNext:%[1-9][0-9]*]] //SPV: [[TYPE_pLinkedNode:%[1-9][0-9]*]] = OpExtInst %void %{{[0-9]*}} DebugTypePointer [[FORWARD_LinkedNode]] //SPV: [[MEMBER_pNext]] = {{.*}} DebugTypeMember [[STRING_pNext]] [[TYPE_pLinkedNode]] - LinkedNode *pNext; + LinkedNode *pNext = {}; }; //SPV: OpExtInst %void %{{[0-9]*}} DebugTypeComposite [[STRING_LinkedNode]] {{.*}} [[MEMBER_pNext]] diff --git a/tests/spirv/debug-value-dynamic-index.slang b/tests/spirv/debug-value-dynamic-index.slang index 591b1f6dad..4a5e63c15a 100644 --- a/tests/spirv/debug-value-dynamic-index.slang +++ b/tests/spirv/debug-value-dynamic-index.slang @@ -2,9 +2,9 @@ struct TestType { - float memberA; - float3 memberB; - float arrayVal[10]; + float memberA = {}; + float3 memberB = {}; + float arrayVal[10] = {}; RWStructuredBuffer memberC; float getValue() { diff --git a/tests/spirv/large-struct-pack.slang b/tests/spirv/large-struct-pack.slang index df15ac67c0..3e7d2c3f35 100644 --- a/tests/spirv/large-struct-pack.slang +++ b/tests/spirv/large-struct-pack.slang @@ -8,7 +8,7 @@ struct WorkData { - int B[1024]; + int B[1024] = {}; }; //TEST_INPUT:set resultBuffer = out ubuffer(data=[0 0 0 0], stride=4, count=1024) diff --git a/tests/spirv/mutating-method-syn.slang b/tests/spirv/mutating-method-syn.slang index 14adc001f7..fb3bb7c9cb 100644 --- a/tests/spirv/mutating-method-syn.slang +++ b/tests/spirv/mutating-method-syn.slang @@ -10,7 +10,7 @@ interface IFoo struct Val : IFoo { - int x; + int x = {}; int bar(int y) { 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 b580ff8fe3..8c5d01186e 100644 --- a/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp +++ b/tools/slang-unit-test/unit-test-decl-tree-reflection.cpp @@ -42,7 +42,7 @@ SLANG_UNIT_TEST(declTreeReflection) // Source for a module that contains an undecorated entrypoint. const char* userSourceBody = R"( [__AttributeUsage(_AttributeTargets.Function)] - struct MyFuncPropertyAttribute {int v;} + struct MyFuncPropertyAttribute {int v = {};} [MyFuncProperty(1024)] [Differentiable] @@ -57,13 +57,13 @@ SLANG_UNIT_TEST(declTreeReflection) struct MyType { - int x; + int x = {}; float f(float x) { return x; } } struct MyGenericType { - T z; + T z = {}; __init(T _z) { z = _z; } @@ -79,7 +79,7 @@ SLANG_UNIT_TEST(declTreeReflection) { struct MyStruct { - int x; + int x = {}; } } @@ -118,10 +118,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, 1 constructor (memberwise ctor), 1 funcDecl ($ZeroInit) + // First declaration should be a struct with 1 variable, 1 constructor (memberwise ctor), 1 funcDecl ($ZeroInit), 1 default ctor auto firstDecl = moduleDeclReflection->getChild(0); SLANG_CHECK(firstDecl->getKind() == slang::DeclReflection::Kind::Struct); - SLANG_CHECK(firstDecl->getChildrenCount() == 3); + SLANG_CHECK(firstDecl->getChildrenCount() == 4); { slang::TypeReflection* type = firstDecl->getType();