summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-check-expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-check-expr.cpp')
-rw-r--r--source/slang/slang-check-expr.cpp68
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;