summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2021-02-17 19:04:48 -0500
committerGitHub <noreply@github.com>2021-02-17 16:04:48 -0800
commit360d4f7a17a066cc878cdb2c558464bfdeaa3418 (patch)
tree99133158bb0cae370c70ce060344ca1acbe958a2
parente59aee131b6d51236613bc374cfa2d5f3b54efe1 (diff)
More #line improvements (#1713)
* #include an absolute path didn't work - because paths were taken to always be relative. * WIP: First pass in supporting output of line error information. * Add support for lexing to better be able to indicate SourceLocation information. * Fix lexer usage in DiagnosticSink in C++ extractor. * Update diagnostics tests to have line location info. * Fixed test expected output that now have source location information in them. * Better handling of tab. * Fix test expected results for tabbing change. * DiagnosticLexer -> DiagnosticSink::SourceLocationLexer Added line continuation tests. * Fix typo. * Added String::appendRepeatedChar * Change to rerun tests. * Added source locations to IR dumping. * Output column for IR dump source loc. * Add support for closing brace location to AST. Use closing brace location in lowering when adding return void. * Set the source location through SourceLoc - simplifies identifying if current loc is valid. * Copy terminator sloc. * Test for improved #line handling. * Made writer the last parameter for dumpIR. Small improvements to comments. * Disable sloc output on dump IR by default. * Fix issue with #line and inlining. * Fix for output with improved #line output. * Small comment change - mainly to kick off TC build. Co-authored-by: Tim Foley <tfoleyNV@users.noreply.github.com>
-rw-r--r--source/slang/slang-ast-stmt.h3
-rw-r--r--source/slang/slang-emit-c-like.cpp18
-rw-r--r--source/slang/slang-emit-source-writer.cpp61
-rw-r--r--source/slang/slang-emit-source-writer.h10
-rw-r--r--source/slang/slang-emit.cpp6
-rw-r--r--source/slang/slang-ir-ssa.cpp5
-rw-r--r--source/slang/slang-ir.cpp75
-rw-r--r--source/slang/slang-ir.h51
-rw-r--r--source/slang/slang-lower-to-ir.cpp17
-rw-r--r--source/slang/slang-parser.cpp35
-rw-r--r--source/slang/slang-source-loc.cpp55
-rw-r--r--source/slang/slang-source-loc.h8
-rw-r--r--tests/compute/half-texture.slang.1.expected2
-rw-r--r--tests/diagnostics/local-line.slang45
-rw-r--r--tests/diagnostics/local-line.slang.expected1
15 files changed, 337 insertions, 55 deletions
diff --git a/source/slang/slang-ast-stmt.h b/source/slang/slang-ast-stmt.h
index 07fc9eeb5..20f9e270e 100644
--- a/source/slang/slang-ast-stmt.h
+++ b/source/slang/slang-ast-stmt.h
@@ -28,6 +28,9 @@ class BlockStmt : public ScopeStmt
{
SLANG_AST_CLASS(BlockStmt)
+ /// TODO(JS): Having ranges of sourcelocs might be a good addition to AST nodes in general.
+ SourceLoc closingSourceLoc; ///< The source location of the closing brace
+
Stmt* body = nullptr;
};
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index 570d48156..0bd6efad3 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -323,9 +323,9 @@ void CLikeSourceEmitter::emitTypeImpl(IRType* type, const StringSliceLoc* nameAn
{
if (nameAndLoc)
{
- // TODO(JS): No call to the previous version of this method was passing in a typeLoc, so disabled for
- // now for simplicity
- //m_writer->advanceToSourceLocation(typeLoc);
+ // We advance here, such that if there is a #line directive to output it will
+ // be done so before the type name appears.
+ m_writer->advanceToSourceLocationIfValid(nameAndLoc->loc);
EDeclarator nameDeclarator;
nameDeclarator.flavor = EDeclarator::Flavor::Name;
@@ -1986,7 +1986,16 @@ void CLikeSourceEmitter::_emitInst(IRInst* inst)
return;
}
- m_writer->advanceToSourceLocation(inst->sourceLoc);
+ // Specially handle params. The issue here is around PHI nodes, and that they do not
+ // have source loc information, by default, but we don't want to force outputting a #line.
+ if (inst->getOp() == kIROp_Param)
+ {
+ m_writer->advanceToSourceLocationIfValid(inst->sourceLoc);
+ }
+ else
+ {
+ m_writer->advanceToSourceLocation(inst->sourceLoc);
+ }
switch(inst->getOp())
{
@@ -2694,6 +2703,7 @@ void CLikeSourceEmitter::emitSimpleFuncImpl(IRFunc* func)
auto name = getName(func);
emitFuncDecorations(func);
+
emitType(resultType, name);
emitSimpleFuncParamsImpl(func);
emitSemantics(func);
diff --git a/source/slang/slang-emit-source-writer.cpp b/source/slang/slang-emit-source-writer.cpp
index 8deecc846..29a83a1fc 100644
--- a/source/slang/slang-emit-source-writer.cpp
+++ b/source/slang/slang-emit-source-writer.cpp
@@ -152,19 +152,19 @@ void SourceWriter::emit(Name* name)
void SourceWriter::emit(const NameLoc& nameAndLoc)
{
- advanceToSourceLocation(nameAndLoc.loc);
+ advanceToSourceLocationIfValid(nameAndLoc.loc);
emit(getText(nameAndLoc.name));
}
void SourceWriter::emit(const StringSliceLoc& nameAndLoc)
{
- advanceToSourceLocation(nameAndLoc.loc);
+ advanceToSourceLocationIfValid(nameAndLoc.loc);
emit(nameAndLoc.name);
}
void SourceWriter::emitName(Name* name, const SourceLoc& locIn)
{
- advanceToSourceLocation(locIn);
+ advanceToSourceLocationIfValid(locIn);
emit(name);
}
@@ -251,19 +251,58 @@ void SourceWriter::emit(double value)
emit(stream.str().c_str());
}
-void SourceWriter::advanceToSourceLocation(const SourceLoc& sourceLocation)
+void SourceWriter::advanceToSourceLocationIfValid(const SourceLoc& sourceLocation)
{
- advanceToSourceLocation(getSourceManager()->getHumaneLoc(sourceLocation));
+ if (sourceLocation.isValid())
+ {
+ advanceToSourceLocation(sourceLocation);
+ }
}
-void SourceWriter::advanceToSourceLocation(const HumaneSourceLoc& sourceLocation)
+void SourceWriter::advanceToSourceLocation(const SourceLoc& sourceLocation)
{
- // Skip invalid locations
- if (sourceLocation.line <= 0)
+ if (getLineDirectiveMode() == LineDirectiveMode::None)
+ {
+ // Ignore if we aren't outputting directives
+ return;
+ }
+
+ if (!sourceLocation.isValid())
+ {
+ // If it's not valid, we will just keep the current location.
+
+ // The question now is if we want to trigger outputting the source location again. We do so if
+ // * The nextSourceLoc is valid
+ // * The line number on the output is different from that location
+ m_needToUpdateSourceLocation = m_needToUpdateSourceLocation || (m_nextSourceLoc.isValid() && m_nextHumaneSourceLocation.line != m_loc.line);
return;
+ }
+
+ // Even if the source location is the same, we still want to trigger output, as long
+ // as we have a valid line location.
+ if (sourceLocation == m_nextSourceLoc)
+ {
+ // This is important because we can end up with many instructions with the same source location - for example
+ // when we have [__unsafeForceInlineEarly] all the inlined instructions get the same location.
+ // When we output lines of source, the target sources line numbers change, therefore we need to
+ // output the same #line directive multiple times.
+
+ m_needToUpdateSourceLocation = m_needToUpdateSourceLocation || (m_nextHumaneSourceLocation.line > 0);
+ return;
+ }
+
+ // Workout the humane source location.
+ const HumaneSourceLoc humaneSourceLoc = getSourceManager()->getHumaneLoc(sourceLocation);
+
+ // If the location is valid, mark need to update, and the new location
+ if (humaneSourceLoc.line > 0)
+ {
+ m_needToUpdateSourceLocation = true;
+ m_nextHumaneSourceLocation = humaneSourceLoc;
+ }
- m_needToUpdateSourceLocation = true;
- m_nextSourceLocation = sourceLocation;
+ // Either way set this as the current source location.
+ m_nextSourceLoc = sourceLocation;
}
void SourceWriter::_flushSourceLocationChange()
@@ -276,7 +315,7 @@ void SourceWriter::_flushSourceLocationChange()
// advances the location, and outputting text is what
// triggers this flush operation.
m_needToUpdateSourceLocation = false;
- _emitLineDirectiveIfNeeded(m_nextSourceLocation);
+ _emitLineDirectiveIfNeeded(m_nextHumaneSourceLocation);
}
void SourceWriter::_emitLineDirectiveAndUpdateSourceLocation(const HumaneSourceLoc& sourceLocation)
diff --git a/source/slang/slang-emit-source-writer.h b/source/slang/slang-emit-source-writer.h
index dfaf40b31..64dc59801 100644
--- a/source/slang/slang-emit-source-writer.h
+++ b/source/slang/slang-emit-source-writer.h
@@ -55,7 +55,8 @@ public:
/// Move the current source location to that specified
void advanceToSourceLocation(const SourceLoc& sourceLocation);
- void advanceToSourceLocation(const HumaneSourceLoc& sourceLocation);
+ /// Only advances if the sourceLocation is valid
+ void advanceToSourceLocationIfValid(const SourceLoc& sourceLocation);
/// Get the content as a string
String getContent() { return m_builder.ProduceString(); }
@@ -96,9 +97,12 @@ protected:
// Current source position for tracking purposes...
HumaneSourceLoc m_loc;
- HumaneSourceLoc m_nextSourceLocation;
- bool m_needToUpdateSourceLocation = false;
+ SourceLoc m_nextSourceLoc;
+ HumaneSourceLoc m_nextHumaneSourceLocation;
+
+ bool m_needToUpdateSourceLocation = false;
+
// Are we at the start of a line, so that we should indent
// before writing any other text?
bool m_isAtStartOfLine = true;
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index c9de26217..dc4709d11 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -136,7 +136,11 @@ static void dumpIRIfEnabled(
if(compileRequest->shouldDumpIR)
{
DiagnosticSinkWriter writer(compileRequest->getSink());
- dumpIR(irModule, &writer, label);
+
+ IRDumpOptions options;
+ options.sourceManager = compileRequest->getSourceManager();
+
+ dumpIR(irModule, options, label, &writer);
}
}
diff --git a/source/slang/slang-ir-ssa.cpp b/source/slang/slang-ir-ssa.cpp
index 8d561fa05..14198aa0a 100644
--- a/source/slang/slang-ir-ssa.cpp
+++ b/source/slang/slang-ir-ssa.cpp
@@ -1109,7 +1109,7 @@ void constructSSA(ConstructSSAContext* context)
}
}
- // Some blocks may now need to pass along arguments to their sucessor,
+ // Some blocks may now need to pass along arguments to their successor,
// which have been stored into the `SSABlockInfo::successorArgs` field.
for(auto bb : globalVal->getBlocks())
{
@@ -1156,6 +1156,9 @@ void constructSSA(ConstructSSAContext* context)
//
oldTerminator->transferDecorationsTo(newTerminator);
+ // Copy the source location of the old terminator to the new terminator
+ newTerminator->sourceLoc = oldTerminator->sourceLoc;
+
// A terminator better not have uses, so we shouldn't have
// to replace them.
SLANG_ASSERT(!oldTerminator->firstUse);
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 5a01dd90a..945cf488f 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -4307,8 +4307,10 @@ namespace Slang
{
StringBuilder* builder = nullptr;
int indent = 0;
- IRDumpMode mode = IRDumpMode::Simplified;
+ IRDumpOptions options;
+ PathInfo lastPathInfo = PathInfo::makeUnknown();
+
Dictionary<IRInst*, String> mapValueToName;
Dictionary<String, UInt> uniqueNameCounters;
UInt uniqueIDCounter = 1;
@@ -4393,7 +4395,7 @@ namespace Slang
// a nice-to-have rather than a maintenance problem
// waiting to happen.
- // Allow an empty nam
+ // Allow an empty name
// Special case a name that is the empty string, just in case.
if(name.getLength() == 0)
{
@@ -4636,7 +4638,7 @@ namespace Slang
// in the "detailed" mode, so that we always
// accurately reflect the structure of the IR.
//
- if(context->mode == IRDumpMode::Detailed)
+ if(context->options.mode == IRDumpOptions::Mode::Detailed)
return false;
if(as<IRConstant>(inst))
@@ -5044,6 +5046,49 @@ namespace Slang
dumpIndent(context);
dumpInstBody(context, inst);
+
+ // Output the originating source location
+ {
+ SourceManager* sourceManager = context->options.sourceManager;
+ if (sourceManager && context->options.flags & IRDumpOptions::Flag::SourceLocations)
+ {
+ StringBuilder buf;
+ buf << " loc: ";
+
+ // Output the line number information
+ if (inst->sourceLoc.isValid())
+ {
+ // Might want to output actual, but nominal is okay for default
+ const SourceLocType sourceLocType = SourceLocType::Nominal;
+
+ // Get the source location
+ const HumaneSourceLoc humaneLoc = sourceManager->getHumaneLoc(inst->sourceLoc, sourceLocType);
+ if (humaneLoc.line >= 0)
+ {
+ buf << humaneLoc.line << "," << humaneLoc.column;
+
+ if (humaneLoc.pathInfo != context->lastPathInfo)
+ {
+ buf << " ";
+ // Output the the location
+ humaneLoc.pathInfo.appendDisplayName(buf);
+ context->lastPathInfo = humaneLoc.pathInfo;
+ }
+ }
+ else
+ {
+ buf << "not found";
+ }
+ }
+ else
+ {
+ buf << "na";
+ }
+
+ dump(context, buf.getUnownedSlice());
+ }
+ }
+
dump(context, "\n");
}
@@ -5057,24 +5102,24 @@ namespace Slang
}
}
- void printSlangIRAssembly(StringBuilder& builder, IRModule* module, IRDumpMode mode)
+ void printSlangIRAssembly(StringBuilder& builder, IRModule* module, const IRDumpOptions& options)
{
IRDumpContext context;
context.builder = &builder;
context.indent = 0;
- context.mode = mode;
-
+ context.options = options;
+
dumpIRModule(&context, module);
}
- void dumpIR(IRInst* globalVal, ISlangWriter* writer, IRDumpMode mode)
+ void dumpIR(IRInst* globalVal, const IRDumpOptions& options, ISlangWriter* writer)
{
StringBuilder sb;
IRDumpContext context;
context.builder = &sb;
context.indent = 0;
- context.mode = mode;
+ context.options = options;
dumpInst(&context, globalVal);
@@ -5082,9 +5127,9 @@ namespace Slang
writer->flush();
}
- void dumpIR(IRModule* module, ISlangWriter* slangWriter, char const* label)
+ void dumpIR(IRModule* module, const IRDumpOptions& options, char const* label, ISlangWriter* inWriter)
{
- WriterHelper writer(slangWriter);
+ WriterHelper writer(inWriter);
if (label)
{
@@ -5093,7 +5138,7 @@ namespace Slang
writer.put(":\n");
}
- dumpIR(module, slangWriter, IRDumpMode::Simplified);
+ dumpIR(module, options, inWriter);
if (label)
{
@@ -5101,16 +5146,16 @@ namespace Slang
}
}
- String getSlangIRAssembly(IRModule* module, IRDumpMode mode)
+ String getSlangIRAssembly(IRModule* module, const IRDumpOptions& options)
{
StringBuilder sb;
- printSlangIRAssembly(sb, module, mode);
+ printSlangIRAssembly(sb, module, options);
return sb;
}
- void dumpIR(IRModule* module, ISlangWriter* writer, IRDumpMode mode)
+ void dumpIR(IRModule* module, const IRDumpOptions& options, ISlangWriter* writer)
{
- String ir = getSlangIRAssembly(module, mode);
+ String ir = getSlangIRAssembly(module, options);
writer->write(ir.getBuffer(), ir.getLength());
writer->flush();
}
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index 56904b53e..ce3a5c29a 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -1473,21 +1473,33 @@ struct IRModule : RefObject
IRModuleInst* moduleInst;
};
- /// How much detail to include in dumped IR.
- ///
- /// Used with the `dumpIR` functions to determine
- /// whether a completely faithful, but verbose, IR
- /// dump is produced, or something simplified for ease
- /// or reading.
- ///
-enum class IRDumpMode
+
+struct IRDumpOptions
{
+ typedef uint32_t Flags;
+ struct Flag
+ {
+ enum Enum : Flags
+ {
+ SourceLocations = 0x1, ///< If set will output source locations
+ };
+ };
+
+ /// How much detail to include in dumped IR.
+ ///
+ /// Used with the `dumpIR` functions to determine
+ /// whether a completely faithful, but verbose, IR
+ /// dump is produced, or something simplified for ease
+ /// or reading.
+ ///
+ enum class Mode
+ {
/// Produce a simplified IR dump.
///
/// Simplified IR dumping will skip certain instructions
/// and print them at their use sites instead, so that
/// the overall dump is shorter and easier to read.
- Simplified,
+ Simplified,
/// Produce a detailed/accurate IR dump.
///
@@ -1495,15 +1507,24 @@ enum class IRDumpMode
/// the instructions that were present with no attempt
/// to selectively skip them or give special formatting.
///
- Detailed,
+ Detailed,
+ };
+
+ Mode mode = Mode::Simplified;
+ /// Flags to control output
+ /// Add Flag::SourceLocations to output source locations set on IR
+ Flags flags = 0;
+
+ /// Must be set if source location output is desired
+ SourceManager* sourceManager = nullptr;
};
-void printSlangIRAssembly(StringBuilder& builder, IRModule* module, IRDumpMode mode = IRDumpMode::Simplified);
-String getSlangIRAssembly(IRModule* module, IRDumpMode mode = IRDumpMode::Simplified);
+void printSlangIRAssembly(StringBuilder& builder, IRModule* module, const IRDumpOptions& options);
+String getSlangIRAssembly(IRModule* module, const IRDumpOptions& options);
-void dumpIR(IRModule* module, ISlangWriter* writer, IRDumpMode mode = IRDumpMode::Simplified);
-void dumpIR(IRInst* globalVal, ISlangWriter* writer, IRDumpMode mode = IRDumpMode::Simplified);
-void dumpIR(IRModule* module, ISlangWriter* slangWriter, char const* label);
+void dumpIR(IRModule* module, const IRDumpOptions& options, ISlangWriter* writer);
+void dumpIR(IRInst* globalVal, const IRDumpOptions& options, ISlangWriter* writer);
+void dumpIR(IRModule* module, const IRDumpOptions& options, char const* label, ISlangWriter* writer);
IRInst* createEmptyInst(
IRModule* module,
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 9b1c4b1a6..ef4cb98ec 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -7043,7 +7043,16 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
{
// `void`-returning function can get an implicit
// return on exit of the body statement.
- subContext->irBuilder->emitReturn();
+ IRInst* returnInst = subContext->irBuilder->emitReturn();
+
+ if (BlockStmt* blockStmt = as<BlockStmt>(decl->body))
+ {
+ returnInst->sourceLoc = blockStmt->closingSourceLoc;
+ }
+ else
+ {
+ returnInst->sourceLoc = SourceLoc();
+ }
}
else
{
@@ -7938,7 +7947,11 @@ IRModule* generateIRForTranslationUnit(
if(compileRequest->shouldDumpIR)
{
DiagnosticSinkWriter writer(compileRequest->getSink());
- dumpIR(module, &writer, "LOWER-TO-IR");
+
+ IRDumpOptions options;
+ options.sourceManager = compileRequest->getSourceManager();
+
+ dumpIR(module, options, "LOWER-TO-IR", &writer);
}
return module;
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 68d06714d..493e707c2 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -557,6 +557,16 @@ namespace Slang
return false;
}
+ bool AdvanceIf(Parser* parser, TokenType tokenType, Token* outToken)
+ {
+ if (parser->LookAheadToken(tokenType))
+ {
+ *outToken = parser->ReadToken();
+ return true;
+ }
+ return false;
+ }
+
// Consume a token and return true it if matches, otherwise false
bool AdvanceIf(Parser* parser, char const* text)
{
@@ -590,6 +600,24 @@ namespace Slang
return false;
}
+ bool AdvanceIfMatch(Parser* parser, TokenType tokenType, Token* outToken)
+ {
+ // If we've run into a syntax error, but haven't recovered inside
+ // the block, then try to recover here.
+ if (parser->isRecovering)
+ {
+ TryRecoverBefore(parser, tokenType);
+ }
+ if (AdvanceIf(parser, tokenType, outToken))
+ return true;
+ if (parser->tokenReader.peekTokenType() == TokenType::EndOfFile)
+ {
+ *outToken = parser->ReadToken(tokenType);
+ return true;
+ }
+ return false;
+ }
+
NodeBase* parseTypeDef(Parser* parser, void* /*userData*/)
{
TypeDefDecl* typeDefDecl = parser->astBuilder->create<TypeDefDecl>();
@@ -3925,7 +3953,9 @@ namespace Slang
{
FillPosition(blockStatement);
}
- while (!AdvanceIfMatch(this, TokenType::RBrace))
+
+ Token closingBraceToken;
+ while (!AdvanceIfMatch(this, TokenType::RBrace, &closingBraceToken))
{
auto stmt = ParseStatement();
if(stmt)
@@ -3952,6 +3982,9 @@ namespace Slang
}
PopScope();
+ // Save the closing braces source loc
+ blockStatement->closingSourceLoc = closingBraceToken.loc;
+
if(!body)
{
body = astBuilder->create<EmptyStmt>();
diff --git a/source/slang/slang-source-loc.cpp b/source/slang/slang-source-loc.cpp
index f6b0afcc1..4b9e16b8e 100644
--- a/source/slang/slang-source-loc.cpp
+++ b/source/slang/slang-source-loc.cpp
@@ -21,6 +21,61 @@ const String PathInfo::getMostUniqueIdentity() const
}
}
+bool PathInfo::operator==(const ThisType& rhs) const
+{
+ // They must be the same type
+ if (type != rhs.type)
+ {
+ return false;
+ }
+
+ switch (type)
+ {
+ case Type::TokenPaste:
+ case Type::TypeParse:
+ case Type::Unknown:
+ case Type::CommandLine:
+ {
+ return true;
+ }
+ case Type::Normal:
+ {
+ return foundPath == rhs.foundPath && uniqueIdentity == rhs.uniqueIdentity;
+ }
+ case Type::FromString:
+ case Type::FoundPath:
+ {
+ // Only have a found path
+ return foundPath == rhs.foundPath;
+ }
+ default: break;
+ }
+
+ return false;
+}
+
+void PathInfo::appendDisplayName(StringBuilder& out) const
+{
+ switch (type)
+ {
+ case Type::TokenPaste: out << "[Token Paste]"; break;
+ case Type::TypeParse: out << "[Type Parse]"; break;
+ case Type::Unknown: out << "[Unknown]"; break;
+ case Type::CommandLine: out << "[Command Line]"; break;
+ case Type::Normal:
+ case Type::FromString:
+ case Type::FoundPath:
+ {
+ // TODO(JS): We might want to escape the path here if necessary
+ out.appendChar('"');
+ out << foundPath;
+ out.appendChar('"');
+ break;
+ }
+ default: break;
+ }
+}
+
/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceView !!!!!!!!!!!!!!!!!!!!!!!!!!!! */
int SourceView::findEntryIndex(SourceLoc sourceLoc) const
diff --git a/source/slang/slang-source-loc.h b/source/slang/slang-source-loc.h
index 1e91a9d62..ef8b49c3b 100644
--- a/source/slang/slang-source-loc.h
+++ b/source/slang/slang-source-loc.h
@@ -40,6 +40,8 @@ interpretation for that lex/parse.
struct PathInfo
{
+ typedef PathInfo ThisType;
+
/// To be more rigorous about where a path comes from, the type identifies what a paths origin is
enum class Type : uint8_t
{
@@ -59,9 +61,15 @@ struct PathInfo
/// True if has a found path that has originated from a file (as opposed to string or some other origin)
SLANG_FORCE_INLINE bool hasFileFoundPath() const { return (type == Type::Normal || type == Type::FoundPath) && foundPath.getLength() > 0; }
+ bool operator==(const ThisType& rhs) const;
+ bool operator!=(const ThisType& rhs) const { return !(*this == rhs); }
+
/// Returns the 'most unique' identity for the path. If has a 'uniqueIdentity' returns that, else the foundPath, else "".
const String getMostUniqueIdentity() const;
+ /// Append to out, how to display the path
+ void appendDisplayName(StringBuilder& out) const;
+
// So simplify construction. In normal usage it's safer to use make methods over constructing directly.
static PathInfo makeUnknown() { return PathInfo { Type::Unknown, String(), String() }; }
static PathInfo makeTokenPaste() { return PathInfo{ Type::TokenPaste, "token paste", String()}; }
diff --git a/tests/compute/half-texture.slang.1.expected b/tests/compute/half-texture.slang.1.expected
index 1e1a282fa..7dd96403f 100644
--- a/tests/compute/half-texture.slang.1.expected
+++ b/tests/compute/half-texture.slang.1.expected
@@ -39,8 +39,6 @@ void computeMain(vector<uint,3> dispatchThreadID_0 : SV_DISPATCHTHREADID)
int index_0 = pos_0.x + pos_0.y * int(4);
outputBuffer_0[(uint) index_0] = index_0;
-
-#line 18
return;
}
diff --git a/tests/diagnostics/local-line.slang b/tests/diagnostics/local-line.slang
new file mode 100644
index 000000000..1cdeba7e4
--- /dev/null
+++ b/tests/diagnostics/local-line.slang
@@ -0,0 +1,45 @@
+//TEST:SIMPLE_LINE:-entry computeMain -target spirv -stage compute
+//TEST:SIMPLE_LINE:-entry computeMain -target dxil -profile cs_6_0
+//TEST:SIMPLE_LINE:-entry computeMain -target dxbc -stage compute
+//TEST:SIMPLE_LINE:-entry computeMain -target dll -stage compute
+//TEST:SIMPLE_LINE:-entry computeMain -target ptx -stage compute
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+int doThing(int a, int b)
+{
+ while (b >= 0)
+ {
+ a
+ +=
+ a;
+ }
+
+ return a;
+}
+
+[numthreads(4, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ int a = dispatchThreadID.x;
+ int b = dispatchThreadID.y;
+ int c = dispatchThreadID.z;
+ int d = a + b * c;
+ int e = d + c / 2;
+
+ for (int i = 0; i < b; ++i)
+ {
+ if (e > 10 && i & 2)
+ {
+ a += b; b -= c; c += c; d = d + e + a; e = a;
+ }
+ else
+ {
+ a = e; b = c + c; d += d + __SyntaxError(); e = doThing(e, dispatchThreadID.x);
+
+ }
+ }
+
+ outputBuffer[dispatchThreadID.x] = a + b + c + d + e;
+}
diff --git a/tests/diagnostics/local-line.slang.expected b/tests/diagnostics/local-line.slang.expected
new file mode 100644
index 000000000..a2720097d
--- /dev/null
+++ b/tests/diagnostics/local-line.slang.expected
@@ -0,0 +1 @@
+39