summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-10-10 17:31:01 -0700
committerGitHub <noreply@github.com>2025-10-11 00:31:01 +0000
commitfb34bafd37e3509d51686ee2a5392d2d8e29d7c5 (patch)
treeca16f2f53595d730319396320b21ad15fada7a06 /source
parentc99addbf2e8a0210b97dad2827045dad95765d08 (diff)
Add diagnostic for cyclic #include. (#8679)
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-diagnostic-defs.h1
-rw-r--r--source/slang/slang-preprocessor.cpp34
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);