diff options
Diffstat (limited to 'source/slang/check.cpp')
| -rw-r--r-- | source/slang/check.cpp | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index e8fd16b94..f12e7e55d 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -5622,6 +5622,115 @@ namespace Slang } }; + bool isPrimaryDecl( + CallableDecl* decl) + { + assert(decl); + return (!decl->primaryDecl) || (decl == decl->primaryDecl); + } + + void validateEntryPoint( + EntryPointRequest* entryPoint) + { + // The first step in validating the entry point is to find + // the (unique) function declaration that matches its 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(entryPoint->name, firstDeclWithName) ) + { + // If there doesn't appear to be any such declaration, then + // we need to diagnose it as an error, and then bail out. + sink->diagnose(translationUnitSyntax, Diagnostics::entryPointFunctionNotFound, entryPoint->name); + return; + } + + // 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, entryPoint->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; + } + } + } + + // Did we find a function declaration in our search? + if(!entryPointFuncDecl) + { + // If not, then we need to diagnose the error. + // For convenience, we will point to the first + // declaration with the right name, that wasn't a function. + sink->diagnose(firstDeclWithName, Diagnostics::entryPointSymbolNotAFunction, entryPoint->name); + return; + } + + // TODO: it is possible that the entry point was declared with + // profile or target overloading. Is there anything that we need + // to do at this point to filter out declarations that aren't + // relevant to the selected profile for the entry point? + + // Phew, we have at least found a suitable decl. + // Let's record that in the entry-point request so + // that we don't have to re-do this effort again later. + entryPoint->decl = entryPointFuncDecl; + + // TODO: after all that work, we are now in a position to start + // validating the declaration itself. E.g., we should check if + // the declared input/output parameters have suitable semantics, + // if they are of types that are appropriate to the stage, etc. + } + + + void checkTranslationUnit( TranslationUnitRequest* translationUnit) { @@ -5630,9 +5739,28 @@ namespace Slang translationUnit->compileRequest, translationUnit); + // Apply the visitor to do the main semantic + // checking that is required on all declarations + // in the translation unit. visitor.checkDecl(translationUnit->SyntaxNode); + + // Next, do follow-up validation on any entry + // points that the user declared via API or + // command line, to ensure that they meet + // requirements. + // + // Note: We may eventually have syntax to + // identify entry points via a modifier on + // declarations, and in this case they should + // probably get validated as part of orindary + // checking above. + for (auto entryPoint : translationUnit->entryPoints) + { + validateEntryPoint(entryPoint); + } } + // // Get the type to use when referencing a declaration |
