diff options
Diffstat (limited to 'source/slang/slang-check-expr.cpp')
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 68 |
1 files changed, 65 insertions, 3 deletions
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index dc7a2d35b..a31e17123 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -412,6 +412,11 @@ namespace Slang expr->declRef = declRef; expr->memberOperatorLoc = _getMemberOpLoc(originalExpr); + // If any member declares the following value is a + // write only, we must declare the parent as a write + // only to avoid modifying the child + expr->type.isWriteOnly = baseExpr->type.isWriteOnly || expr->type.isWriteOnly; + // When referring to a member through an expression, // the result is only an l-value if both the base // expression and the member agree that it should be. @@ -424,7 +429,7 @@ namespace Slang // One exception to this is if we're reading the contents // of a GLSL buffer interface block which isn't marked as // read_only - expr->type.isLeftValue = isMutableGLSLBufferBlockVarExpr(baseExpr); + expr->type.isLeftValue = isMutableGLSLBufferBlockVarExpr(baseExpr) && (expr->type.hasReadOnlyOnTarget == false); } else { @@ -2078,6 +2083,9 @@ namespace Slang Expr* SemanticsVisitor::checkAssignWithCheckedOperands(AssignExpr* expr) { + if (expr->right->type.isWriteOnly) + getSink()->diagnose(expr, Diagnostics::readingFromWriteOnly); + expr->left = maybeOpenRef(expr->left); auto type = expr->left->type; auto right = maybeOpenRef(expr->right); @@ -2177,6 +2185,44 @@ namespace Slang return _canLValueCoerceScalarType(a, b); } + + void SemanticsVisitor::compareMemoryQualifierOfParamToArgument( + ParamDecl* paramIn, + Expr* argIn) + { + auto arg = as<VarExpr>(argIn); + if (!paramIn || !arg) + return; + + auto argDeclRef = arg->declRef; + if (!argDeclRef) + return; + auto argDecl = argDeclRef.getDecl(); + auto argMemMods = argDecl->findModifier<MemoryQualifierCollectionModifier>(); + if(!argMemMods) + return; + uint32_t argQualifiers = argMemMods->getMemoryQualifierBit(); + + uint32_t paramQualifiers = 0; + auto paramMemMods = paramIn->findModifier<MemoryQualifierCollectionModifier>(); + if(paramMemMods) + paramQualifiers = paramMemMods->getMemoryQualifierBit(); + + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kCoherent + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kCoherent)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "coherent"); + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kReadOnly + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kReadOnly)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "readonly"); + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kWriteOnly + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kWriteOnly)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "writeonly"); + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kVolatile + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kVolatile)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "volatile"); + // dropping a `restrict` qualifier from arguments is allowed in GLSL with memory qualifiers + } + Expr* SemanticsVisitor::CheckInvokeExprWithCheckedOperands(InvokeExpr *expr) { auto rs = ResolveInvoke(expr); @@ -2194,10 +2240,25 @@ namespace Slang } } + auto funcDeclRefExpr = as<DeclRefExpr>(invoke->functionExpr); + FunctionDeclBase* funcDeclBase = nullptr; + if (funcDeclRefExpr) + funcDeclBase = as<FunctionDeclBase>(funcDeclRefExpr->declRef.getDecl()); + Index paramCount = funcType->getParamCount(); for (Index pp = 0; pp < paramCount; ++pp) { auto paramType = funcType->getParamType(pp); + Expr* argExpr = nullptr; + ParamDecl* paramDecl = nullptr; + if (pp < expr->arguments.getCount()) + { + argExpr = expr->arguments[pp]; + if(funcDeclBase) + paramDecl = funcDeclBase->getParameters()[pp]; + } + compareMemoryQualifierOfParamToArgument(paramDecl, argExpr); + if (as<OutTypeBase>(paramType) || as<RefType>(paramType)) { // `out`, `inout`, and `ref` parameters currently require @@ -2207,9 +2268,8 @@ namespace Slang // for an `inout` parameter to be converted in both // directions. // - if( pp < expr->arguments.getCount() ) + if( argExpr ) { - auto argExpr = expr->arguments[pp]; if( !argExpr->type.isLeftValue) { auto implicitCastExpr = as<ImplicitCastExpr>(argExpr); @@ -3280,6 +3340,8 @@ namespace Slang { auto elementType = QualType(pointerLikeType->getElementType()); elementType.isLeftValue = baseType.isLeftValue; + elementType.hasReadOnlyOnTarget = baseType.hasReadOnlyOnTarget; + elementType.isWriteOnly = baseType.isWriteOnly; auto derefExpr = m_astBuilder->create<DerefExpr>(); derefExpr->base = expr; |
