diff options
Diffstat (limited to 'source/slang')
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-preprocessor.cpp | 34 |
2 files changed, 27 insertions, 8 deletions
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index d31247623..840192a50 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -383,6 +383,7 @@ DIAGNOSTIC(-1, Note, seeOpeningToken, "see opening '$0'") // 153xx - #include DIAGNOSTIC(15300, Error, includeFailed, "failed to find include file '$0'") DIAGNOSTIC(15301, Error, importFailed, "failed to find imported file '$0'") +DIAGNOSTIC(15302, Error, cyclicInclude, "cyclic `#include` of file '$0'") DIAGNOSTIC(-1, Error, noIncludeHandlerSpecified, "no `#include` handler was specified") DIAGNOSTIC( 15302, diff --git a/source/slang/slang-preprocessor.cpp b/source/slang/slang-preprocessor.cpp index a0e80473d..ff3e5294e 100644 --- a/source/slang/slang-preprocessor.cpp +++ b/source/slang/slang-preprocessor.cpp @@ -1288,6 +1288,10 @@ struct Preprocessor /// stop them from being included again. HashSet<String> pragmaOnceUniqueIdentities; + /// The unique identities of any paths that have been included already. + /// This is used to detect cycles in #includes. + HashSet<String> includedFiles; + WarningStateTracker* warningStateTracker = nullptr; /// Name pool to use when creating `Name`s from strings @@ -1316,7 +1320,7 @@ struct Preprocessor SourceLoc::RawValue absoluteSourceLocCounter = 0; /// Push a new input file onto the input stack of the preprocessor - void pushInputFile(InputFile* inputFile, SourceLoc location); + void pushInputFile(InputFile* inputFile, SourceLoc location, String fileIdentity); /// Pop the inner-most input file from the stack of input files void popInputFile(); @@ -3479,7 +3483,7 @@ static SlangResult readFile( return SLANG_OK; } -void Preprocessor::pushInputFile(InputFile* inputFile, SourceLoc loc) +void Preprocessor::pushInputFile(InputFile* inputFile, SourceLoc loc, String fileIdentity) { if (m_currentInputFile) { @@ -3488,13 +3492,12 @@ void Preprocessor::pushInputFile(InputFile* inputFile, SourceLoc loc) absoluteSourceLocCounter += offset; } - { - SourceView* sourceView = inputFile->getLexer()->m_sourceView; - sourceView->setAbsoluteLocationBase(absoluteSourceLocCounter); - } + SourceView* sourceView = inputFile->getLexer()->m_sourceView; + sourceView->setAbsoluteLocationBase(absoluteSourceLocCounter); inputFile->m_parent = m_currentInputFile; m_currentInputFile = inputFile; + includedFiles.add(fileIdentity); } // Handle a `#include` directive @@ -3600,6 +3603,17 @@ static void HandleIncludeDirective(PreprocessorDirectiveContext* context) sourceManager->addSourceFile(filePathInfo.uniqueIdentity, sourceFile); } + auto fileIdentity = sourceFile->getPathInfo().getMostUniqueIdentity(); + if (context->m_preprocessor->includedFiles.contains(fileIdentity)) + { + // This file has already been included, we should diagnose an error and return. + GetSink(context)->diagnose( + pathToken.loc, + Diagnostics::cyclicInclude, + pathToken.getContent()); + return; + } + // If we are running the preprocessor as part of compiling a // specific module, then we must keep track of the file we've // read as yet another file that the module will depend on. @@ -3615,7 +3629,7 @@ static void HandleIncludeDirective(PreprocessorDirectiveContext* context) InputFile* inputFile = new InputFile(context->m_preprocessor, sourceView); - context->m_preprocessor->pushInputFile(inputFile, directiveLoc); + context->m_preprocessor->pushInputFile(inputFile, directiveLoc, fileIdentity); } static void _parseMacroOps( @@ -4624,6 +4638,7 @@ void Preprocessor::popInputFile() auto lastSegment = sourceView->getLastSegment(); absoluteSourceLocCounter += SourceRange(lastSegment.begin, sourceView->getRange().end).getSize(); + includedFiles.remove(sourceView->getSourceFile()->getPathInfo().getMostUniqueIdentity()); } // We will update the current file to the parent of whatever @@ -4957,7 +4972,10 @@ TokenList preprocessSource( // create an initial input stream based on the provided buffer InputFile* primaryInputFile = new InputFile(&preprocessor, sourceView); - preprocessor.pushInputFile(primaryInputFile, sourceView->getRange().begin); + preprocessor.pushInputFile( + primaryInputFile, + sourceView->getRange().begin, + file->getPathInfo().getMostUniqueIdentity()); } TokenList tokens = ReadAllTokens(&preprocessor); |
