summaryrefslogtreecommitdiffstats
path: root/source/slang/check.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/check.cpp')
-rw-r--r--source/slang/check.cpp176
1 files changed, 168 insertions, 8 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index 046587d0f..1fa7f9b01 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -1845,6 +1845,38 @@ namespace Slang
return Stage::Unknown;
}
+ bool hasIntArgs(Attribute* attr, int numArgs)
+ {
+ if (int(attr->args.Count()) != numArgs)
+ {
+ return false;
+ }
+ for (int i = 0; i < numArgs; ++i)
+ {
+ if (!attr->args[i]->As<IntegerLiteralExpr>())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool hasStringArgs(Attribute* attr, int numArgs)
+ {
+ if (int(attr->args.Count()) != numArgs)
+ {
+ return false;
+ }
+ for (int i = 0; i < numArgs; ++i)
+ {
+ if (!attr->args[i]->As<StringLiteralExpr>())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
bool validateAttribute(RefPtr<Attribute> attr)
{
if(auto numThreadsAttr = attr.As<NumThreadsAttribute>())
@@ -1898,7 +1930,27 @@ namespace Slang
entryPointAttr->stage = stage;
}
- else
+ else if ((attr.As<DomainAttribute>()) ||
+ (attr.As<MaxTessFactorAttribute>()) ||
+ (attr.As<OutputTopologyAttribute>()) ||
+ (attr.As<PartitioningAttribute>()) ||
+ (attr.As<PatchConstantFuncAttribute>()))
+ {
+ // Let it go thru iff single string attribute
+ if (!hasStringArgs(attr, 1))
+ {
+ getSink()->diagnose(attr, Diagnostics::expectedSingleStringArg, attr->name);
+ }
+ }
+ else if (attr.As<OutputControlPointsAttribute>())
+ {
+ // Let it go thru iff single integral attribute
+ if (!hasIntArgs(attr, 1))
+ {
+ getSink()->diagnose(attr, Diagnostics::expectedSingleIntArg, attr->name);
+ }
+ }
+ else
{
if(attr->args.Count() == 0)
{
@@ -8231,18 +8283,89 @@ namespace Slang
return type;
}
+
+ FuncDecl* findFunctionDeclByName(EntryPointRequest* entryPoint, Name* name)
+ {
+ auto translationUnit = entryPoint->getTranslationUnit();
+ auto sink = &entryPoint->compileRequest->mSink;
+ auto translationUnitSyntax = translationUnit->SyntaxNode;
+
+ // Make sure we've got a query-able member dictionary
+ buildMemberDictionary(translationUnitSyntax);
+
+ // We will look up any global-scope declarations in the translation
+ // unit that match the name of our entry point.
+ Decl* firstDeclWithName = nullptr;
+ if (!translationUnitSyntax->memberDictionary.TryGetValue(name, firstDeclWithName))
+ {
+ // If there doesn't appear to be any such declaration, then we are done.
+
+ sink->diagnose(translationUnitSyntax, Diagnostics::entryPointFunctionNotFound, name);
+
+ return nullptr;
+ }
+
+ // We found at least one global-scope declaration with the right name,
+ // but (1) it might not be a function, and (2) there might be
+ // more than one function.
+ //
+ // We'll walk the linked list of declarations with the same name,
+ // to see what we find. Along the way we'll keep track of the
+ // first function declaration we find, if any:
+ FuncDecl* entryPointFuncDecl = nullptr;
+ for (auto ee = firstDeclWithName; ee; ee = ee->nextInContainerWithSameName)
+ {
+ // Is this declaration a function?
+ if (auto funcDecl = dynamic_cast<FuncDecl*>(ee))
+ {
+ // Skip non-primary declarations, so that
+ // we don't give an error when an entry
+ // point is forward-declared.
+ if (!isPrimaryDecl(funcDecl))
+ continue;
+
+ // is this the first one we've seen?
+ if (!entryPointFuncDecl)
+ {
+ // If so, this is a candidate to be
+ // the entry point function.
+ entryPointFuncDecl = funcDecl;
+ }
+ else
+ {
+ // Uh-oh! We've already seen a function declaration with this
+ // name before, so the whole thing is ambiguous. We need
+ // to diagnose and bail out.
+
+ sink->diagnose(translationUnitSyntax, Diagnostics::ambiguousEntryPoint, name);
+
+ // List all of the declarations that the user *might* mean
+ for (auto ff = firstDeclWithName; ff; ff = ff->nextInContainerWithSameName)
+ {
+ if (auto candidate = dynamic_cast<FuncDecl*>(ff))
+ {
+ sink->diagnose(candidate, Diagnostics::entryPointCandidate, candidate->getName());
+ }
+ }
+
+ // Bail out.
+ return nullptr;
+ }
+ }
+ }
+
+ return entryPointFuncDecl;
+ }
+
// Validate that an entry point function conforms to any additional
// constraints based on the stage (and profile?) it specifies.
void validateEntryPoint(
- EntryPointRequest* /*entryPoint*/)
+ EntryPointRequest* entryPoint)
{
- // TODO: We currently don't do any checking here, but this is the
+ // TODO: We currently do minimal checking here, but this is the
// right place to perform the following validation checks:
//
- // * Does the entry point specify all of the attributes required
- // by the chosen stage (e.g., a `[domain(...)]` attribute for]
- // a hull shader.
- //
+
// * Are the function input/output parameters and result type
// all valid for the chosen stage? (e.g., there shouldn't be
// an `OutputStream<X>` type in a vertex shader signature)
@@ -8263,6 +8386,43 @@ namespace Slang
// `Texture2D.Sample`, then that should produce an error because
// that function is specific to the fragment profile/stage.
//
+
+ if (entryPoint->getStage() == Stage::Hull)
+ {
+ auto translationUnit = entryPoint->getTranslationUnit();
+ auto sink = &entryPoint->compileRequest->mSink;
+ auto translationUnitSyntax = translationUnit->SyntaxNode;
+
+ auto attr = entryPoint->decl->FindModifier<PatchConstantFuncAttribute>();
+
+ if (attr)
+ {
+ if (attr->args.Count() != 1)
+ {
+ sink->diagnose(translationUnitSyntax, Diagnostics::badlyDefinedPatchConstantFunc, entryPoint->name);
+ return;
+ }
+
+ Expr* expr = attr->args[0];
+ StringLiteralExpr* stringLit = expr->As<StringLiteralExpr>();
+
+ if (!stringLit)
+ {
+ sink->diagnose(translationUnitSyntax, Diagnostics::badlyDefinedPatchConstantFunc, entryPoint->name);
+ return;
+ }
+
+ Name* name = entryPoint->compileRequest->getNamePool()->getName(stringLit->value);
+ FuncDecl* funcDecl = findFunctionDeclByName(entryPoint, name);
+ if (!funcDecl)
+ {
+ sink->diagnose(translationUnitSyntax, Diagnostics::attributeFunctionNotFound, name, "patchconstantfunc");
+ return;
+ }
+
+ attr->patchConstantFuncDecl = funcDecl;
+ }
+ }
}
// Given an `EntryPointRequest` specified via API or command line options,
@@ -8445,7 +8605,7 @@ namespace Slang
// set to `Batman` to know whether the setting for `B` is valid. In this limit
// the constraints can be mutually recursive (so `A : IMentor<B>`).
//
- // The only way to check things corectly is to validate each conformance under
+ // The only way to check things correctly is to validate each conformance under
// a set of assumptions (substitutions) that includes all the type substitutions,
// and possibly also all the other constraints *except* the one to be validated.
//