diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2022-08-22 10:08:25 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-22 10:08:25 -0400 |
| commit | 15055d20c143cb398bd3e269541eebf24777390a (patch) | |
| tree | 81f96a53824765fabc1fbb81d2d588476996eaa9 | |
| parent | af70651a4843b16dd24e14b5cedffe399ebeb862 (diff) | |
Replace DownstreamCompileResult with Artifact (#2369)
* #include an absolute path didn't work - because paths were taken to always be relative.
* WIP replacing DownstreamCompileResult.
* First attempt at replacing DownstreamCompileResult with IArtifact and associated types.
* Small renaming around CharSlice.
* ICastable -> ISlangCastable
Added IClonable
Fix issue with cloning in ArtifactDiagnostics.
* Only add the blob if one is defined in DXC.
* Guard adding blob representation.
* Make cloneInterface available across code base.
Set enums backing type for ArtifactDiagnostic.
* Added ::create for ArtifactDiagnostics.
35 files changed, 1066 insertions, 836 deletions
diff --git a/build/visual-studio/compiler-core/compiler-core.vcxproj b/build/visual-studio/compiler-core/compiler-core.vcxproj index 34ca85ef3..c721d9f81 100644 --- a/build/visual-studio/compiler-core/compiler-core.vcxproj +++ b/build/visual-studio/compiler-core/compiler-core.vcxproj @@ -253,6 +253,7 @@ <ClInclude Include="..\..\..\source\compiler-core\slang-artifact-associated-impl.h" />
<ClInclude Include="..\..\..\source\compiler-core\slang-artifact-associated.h" />
<ClInclude Include="..\..\..\source\compiler-core\slang-artifact-desc-util.h" />
+ <ClInclude Include="..\..\..\source\compiler-core\slang-artifact-diagnostic-util.h" />
<ClInclude Include="..\..\..\source\compiler-core\slang-artifact-handler-impl.h" />
<ClInclude Include="..\..\..\source\compiler-core\slang-artifact-helper.h" />
<ClInclude Include="..\..\..\source\compiler-core\slang-artifact-impl.h" />
@@ -299,6 +300,7 @@ <ItemGroup>
<ClCompile Include="..\..\..\source\compiler-core\slang-artifact-associated-impl.cpp" />
<ClCompile Include="..\..\..\source\compiler-core\slang-artifact-desc-util.cpp" />
+ <ClCompile Include="..\..\..\source\compiler-core\slang-artifact-diagnostic-util.cpp" />
<ClCompile Include="..\..\..\source\compiler-core\slang-artifact-handler-impl.cpp" />
<ClCompile Include="..\..\..\source\compiler-core\slang-artifact-helper.cpp" />
<ClCompile Include="..\..\..\source\compiler-core\slang-artifact-impl.cpp" />
diff --git a/build/visual-studio/compiler-core/compiler-core.vcxproj.filters b/build/visual-studio/compiler-core/compiler-core.vcxproj.filters index a2b1dadc7..70fd9ca5c 100644 --- a/build/visual-studio/compiler-core/compiler-core.vcxproj.filters +++ b/build/visual-studio/compiler-core/compiler-core.vcxproj.filters @@ -18,6 +18,9 @@ <ClInclude Include="..\..\..\source\compiler-core\slang-artifact-desc-util.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\..\..\source\compiler-core\slang-artifact-diagnostic-util.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="..\..\..\source\compiler-core\slang-artifact-handler-impl.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -152,6 +155,9 @@ <ClCompile Include="..\..\..\source\compiler-core\slang-artifact-desc-util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\source\compiler-core\slang-artifact-diagnostic-util.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\source\compiler-core\slang-artifact-handler-impl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -945,7 +945,7 @@ extern "C" /* An interface to provide a mechanism to cast, that doesn't require ref counting and doesn't have to return a pointer to a ISlangUnknown derived class */ - class ICastable : public ISlangUnknown + class ISlangCastable : public ISlangUnknown { SLANG_COM_INTERFACE(0x87ede0e1, 0x4852, 0x44b0, { 0x8b, 0xf2, 0xcb, 0x31, 0x87, 0x4d, 0xe2, 0x39 }); @@ -955,6 +955,17 @@ extern "C" virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) = 0; }; + class ISlangClonable : public ISlangCastable + { + SLANG_COM_INTERFACE(0x1ec36168, 0xe9f4, 0x430d, { 0xbb, 0x17, 0x4, 0x8a, 0x80, 0x46, 0xb3, 0x1f }); + + /// Note the use of guid is for the desired interface/object. + /// The object is returned *not* ref counted. Any type that can implements the interface, + /// derives from ICastable, and so (not withstanding some other issue) will always return + /// an ICastable interface which other interfaces/types are accessible from via castAs + SLANG_NO_THROW virtual void* SLANG_MCALL clone(const SlangUUID& guid) = 0; + }; + /** A "blob" of binary data. This interface definition is compatible with the `ID3DBlob` and `ID3D10Blob` interfaces. @@ -1019,7 +1030,7 @@ extern "C" /** An interface that can be used to encapsulate access to a shared library. An implementation does not have to implement the library as a shared library */ - struct ISlangSharedLibrary : public ICastable + struct ISlangSharedLibrary : public ISlangCastable { SLANG_COM_INTERFACE(0x70dbc7c4, 0xdc3b, 0x4a07, { 0xae, 0x7e, 0x75, 0x2a, 0xf6, 0xa8, 0x15, 0x55 }) @@ -1276,6 +1287,7 @@ extern "C" namespace slang { struct IGlobalSession; struct ICompileRequest; + } // namespace slang /*! diff --git a/source/compiler-core/slang-artifact-associated-impl.cpp b/source/compiler-core/slang-artifact-associated-impl.cpp index dcca24a7c..9b437b9c0 100644 --- a/source/compiler-core/slang-artifact-associated-impl.cpp +++ b/source/compiler-core/slang-artifact-associated-impl.cpp @@ -7,30 +7,63 @@ #include "../core/slang-io.h" #include "../core/slang-array-view.h" -#include "slang-artifact-util.h" +#include "../core/slang-char-util.h" + +#include "slang-artifact-diagnostic-util.h" namespace Slang { -/* !!!!!!!!!!!!!!!!!!!!!!!!!!! DiagnosticsImpl !!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDiagnostics !!!!!!!!!!!!!!!!!!!!!!!!!!! */ -void* DiagnosticsImpl::getInterface(const Guid& guid) +ArtifactDiagnostics::ArtifactDiagnostics(const ThisType& rhs): + m_result(rhs.m_result), + m_diagnostics(rhs.m_diagnostics), + m_raw(rhs.m_raw.getLength() + 1) +{ + // We need to be careful with raw, we want a new *copy* not a non atomic ref counting + // In initialization we should have enough space + m_raw.append(rhs.m_raw.getUnownedSlice()); + + // Reallocate all the strings + for (auto& diagnostic : m_diagnostics) + { + diagnostic.filePath = m_allocator.allocate(diagnostic.filePath); + diagnostic.code = m_allocator.allocate(diagnostic.code); + diagnostic.text = m_allocator.allocate(diagnostic.text); + } +} + +void* ArtifactDiagnostics::clone(const Guid& guid) +{ + ThisType* copy = new ThisType(*this); + if (auto ptr = copy->castAs(guid)) + { + return ptr; + } + // If the cast fails, we delete the item. + delete copy; + return nullptr; +} + +void* ArtifactDiagnostics::getInterface(const Guid& guid) { if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || - guid == IDiagnostics::getTypeGuid()) + guid == IClonable::getTypeGuid() || + guid == IArtifactDiagnostics::getTypeGuid()) { - return static_cast<IDiagnostics*>(this); + return static_cast<IArtifactDiagnostics*>(this); } return nullptr; } -void* DiagnosticsImpl::getObject(const Guid& guid) +void* ArtifactDiagnostics::getObject(const Guid& guid) { SLANG_UNUSED(guid); return nullptr; } -void* DiagnosticsImpl::castAs(const Guid& guid) +void* ArtifactDiagnostics::castAs(const Guid& guid) { if (auto intf = getInterface(guid)) { @@ -39,42 +72,42 @@ void* DiagnosticsImpl::castAs(const Guid& guid) return getObject(guid); } -void DiagnosticsImpl::reset() +void ArtifactDiagnostics::reset() { m_diagnostics.clear(); - m_raw = ZeroTerminatedCharSlice(); + m_raw.Clear(); m_result = SLANG_OK; - m_arena.deallocateAll(); + m_allocator.deallocateAll(); } -ZeroTerminatedCharSlice DiagnosticsImpl::_allocateSlice(const Slice<char>& in) -{ - if (in.count == 0) - { - return ZeroTerminatedCharSlice("", 0); - } - const char* dst = m_arena.allocateString(in.data, in.count); - return ZeroTerminatedCharSlice(dst, in.count); -} - -void DiagnosticsImpl::add(const Diagnostic& inDiagnostic) +void ArtifactDiagnostics::add(const Diagnostic& inDiagnostic) { Diagnostic diagnostic(inDiagnostic); - diagnostic.text = _allocateSlice(inDiagnostic.text); - diagnostic.code = _allocateSlice(inDiagnostic.code); - diagnostic.filePath = _allocateSlice(inDiagnostic.filePath); + diagnostic.text = m_allocator.allocate(inDiagnostic.text); + diagnostic.code = m_allocator.allocate(inDiagnostic.code); + diagnostic.filePath = m_allocator.allocate(inDiagnostic.filePath); m_diagnostics.add(diagnostic); } -void DiagnosticsImpl::setRaw(const ZeroTerminatedCharSlice& slice) +void ArtifactDiagnostics::setRaw(const CharSlice& slice) +{ + m_raw.Clear(); + m_raw << asStringSlice(slice); +} + +void ArtifactDiagnostics::appendRaw(const CharSlice& slice) { - m_raw = _allocateSlice(slice); + if (m_raw.getLength() && m_raw[m_raw.getLength() - 1] != '\n') + { + m_raw.appendChar('\n'); + } + m_raw << asStringSlice(slice); } -Count DiagnosticsImpl::getCountAtLeastSeverity(Severity severity) +Count ArtifactDiagnostics::getCountAtLeastSeverity(Diagnostic::Severity severity) { Index count = 0; for (const auto& msg : m_diagnostics) @@ -84,7 +117,7 @@ Count DiagnosticsImpl::getCountAtLeastSeverity(Severity severity) return count; } -Count DiagnosticsImpl::getCountBySeverity(Severity severity) +Count ArtifactDiagnostics::getCountBySeverity(Diagnostic::Severity severity) { Index count = 0; for (const auto& msg : m_diagnostics) @@ -94,7 +127,7 @@ Count DiagnosticsImpl::getCountBySeverity(Severity severity) return count; } -bool DiagnosticsImpl::hasOfAtLeastSeverity(Severity severity) +bool ArtifactDiagnostics::hasOfAtLeastSeverity(Diagnostic::Severity severity) { for (const auto& msg : m_diagnostics) { @@ -106,10 +139,10 @@ bool DiagnosticsImpl::hasOfAtLeastSeverity(Severity severity) return false; } -Count DiagnosticsImpl::getCountByStage(Stage stage, Count outCounts[Int(Severity::CountOf)]) +Count ArtifactDiagnostics::getCountByStage(Diagnostic::Stage stage, Count outCounts[Int(Diagnostic::Severity::CountOf)]) { Int count = 0; - ::memset(outCounts, 0, sizeof(Index) * Int(Severity::CountOf)); + ::memset(outCounts, 0, sizeof(Index) * Int(Diagnostic::Severity::CountOf)); for (const auto& diagnostic : m_diagnostics) { if (diagnostic.stage == stage) @@ -121,7 +154,7 @@ Count DiagnosticsImpl::getCountByStage(Stage stage, Count outCounts[Int(Severity return count++; } -void DiagnosticsImpl::removeBySeverity(Severity severity) +void ArtifactDiagnostics::removeBySeverity(Diagnostic::Severity severity) { Index count = m_diagnostics.getCount(); for (Index i = 0; i < count; ++i) @@ -135,51 +168,33 @@ void DiagnosticsImpl::removeBySeverity(Severity severity) } } -void DiagnosticsImpl::maybeAddNote(const ZeroTerminatedCharSlice& in) +void ArtifactDiagnostics::maybeAddNote(const CharSlice& in) { - // Don't bother adding an empty line - if (UnownedStringSlice(in.begin(), in.end()).trim().getLength() == 0) - { - return; - } - - // If there's nothing previous, we'll ignore too, as note should be in addition to - // a pre-existing error/warning - if (m_diagnostics.getCount() == 0) - { - return; - } - - // Make it a note on the output - Diagnostic diagnostic; - - diagnostic.severity = Severity::Info; - diagnostic.text = _allocateSlice(in); - m_diagnostics.add(diagnostic); + ArtifactDiagnosticUtil::maybeAddNote(asStringSlice(in), this); } -void DiagnosticsImpl::requireErrorDiagnostic() +void ArtifactDiagnostics::requireErrorDiagnostic() { // If we find an error, we don't need to add a generic diagnostic for (const auto& msg : m_diagnostics) { - if (Index(msg.severity) >= Index(Severity::Error)) + if (Index(msg.severity) >= Index(Diagnostic::Severity::Error)) { return; } } Diagnostic diagnostic; - diagnostic.severity = Severity::Error; - diagnostic.text = m_raw; + diagnostic.severity = Diagnostic::Severity::Error; + diagnostic.text = m_allocator.allocate(m_raw); // Add the diagnostic m_diagnostics.add(diagnostic); } -/* static */UnownedStringSlice _getSeverityText(IDiagnostics::Severity severity) +/* static */UnownedStringSlice _getSeverityText(ArtifactDiagnostic::Severity severity) { - typedef IDiagnostics::Severity Severity; + typedef ArtifactDiagnostic::Severity Severity; switch (severity) { default: return UnownedStringSlice::fromLiteral("Unknown"); @@ -189,9 +204,9 @@ void DiagnosticsImpl::requireErrorDiagnostic() } } -static void _appendCounts(const Index counts[Int(IDiagnostics::Severity::CountOf)], StringBuilder& out) +static void _appendCounts(const Index counts[Int(ArtifactDiagnostic::Severity::CountOf)], StringBuilder& out) { - typedef IDiagnostics::Severity Severity; + typedef ArtifactDiagnostic::Severity Severity; for (Index i = 0; i < Int(Severity::CountOf); i++) { @@ -202,9 +217,9 @@ static void _appendCounts(const Index counts[Int(IDiagnostics::Severity::CountOf } } -static void _appendSimplified(const Index counts[Int(IDiagnostics::Severity::CountOf)], StringBuilder& out) +static void _appendSimplified(const Index counts[Int(ArtifactDiagnostic::Severity::CountOf)], StringBuilder& out) { - typedef IDiagnostics::Severity Severity; + typedef ArtifactDiagnostic::Severity Severity; for (Index i = 0; i < Int(Severity::CountOf); i++) { if (counts[i] > 0) @@ -214,18 +229,18 @@ static void _appendSimplified(const Index counts[Int(IDiagnostics::Severity::Cou } } -void DiagnosticsImpl::appendSummary(ISlangBlob** outBlob) +void ArtifactDiagnostics::calcSummary(ISlangBlob** outBlob) { StringBuilder buf; - Index counts[Int(Severity::CountOf)]; - if (getCountByStage(Stage::Compile, counts) > 0) + Index counts[Int(Diagnostic::Severity::CountOf)]; + if (getCountByStage(Diagnostic::Stage::Compile, counts) > 0) { buf << "Compile: "; _appendCounts(counts, buf); buf << "\n"; } - if (getCountByStage(Stage::Link, counts) > 0) + if (getCountByStage(Diagnostic::Stage::Link, counts) > 0) { buf << "Link: "; _appendCounts(counts, buf); @@ -235,18 +250,18 @@ void DiagnosticsImpl::appendSummary(ISlangBlob** outBlob) *outBlob = StringBlob::moveCreate(buf).detach(); } -void DiagnosticsImpl::appendSimplifiedSummary(ISlangBlob** outBlob) +void ArtifactDiagnostics::calcSimplifiedSummary(ISlangBlob** outBlob) { StringBuilder buf; - Index counts[Int(Severity::CountOf)]; - if (getCountByStage(Stage::Compile, counts) > 0) + Index counts[Int(Diagnostic::Severity::CountOf)]; + if (getCountByStage(Diagnostic::Stage::Compile, counts) > 0) { buf << "Compile: "; _appendSimplified(counts, buf); buf << "\n"; } - if (getCountByStage(Stage::Link, counts) > 0) + if (getCountByStage(Diagnostic::Stage::Link, counts) > 0) { buf << "Link: "; _appendSimplified(counts, buf); @@ -256,20 +271,20 @@ void DiagnosticsImpl::appendSimplifiedSummary(ISlangBlob** outBlob) *outBlob = StringBlob::moveCreate(buf).detach(); } -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! PostEmitMetadataImpl !!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactPostEmitMetadata !!!!!!!!!!!!!!!!!!!!!!!!!!! */ -void* PostEmitMetadataImpl::getInterface(const Guid& guid) +void* ArtifactPostEmitMetadata::getInterface(const Guid& guid) { if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || - guid == IPostEmitMetadata::getTypeGuid()) + guid == IArtifactPostEmitMetadata::getTypeGuid()) { - return static_cast<IPostEmitMetadata*>(this); + return static_cast<IArtifactPostEmitMetadata*>(this); } return nullptr; } -void* PostEmitMetadataImpl::getObject(const Guid& uuid) +void* ArtifactPostEmitMetadata::getObject(const Guid& uuid) { if (uuid == getTypeGuid()) { @@ -278,7 +293,7 @@ void* PostEmitMetadataImpl::getObject(const Guid& uuid) return nullptr; } -void* PostEmitMetadataImpl::castAs(const Guid& guid) +void* ArtifactPostEmitMetadata::castAs(const Guid& guid) { if (auto ptr = getInterface(guid)) { @@ -287,7 +302,7 @@ void* PostEmitMetadataImpl::castAs(const Guid& guid) return getObject(guid); } -Slice<ShaderBindingRange> PostEmitMetadataImpl::getUsedBindingRanges() +Slice<ShaderBindingRange> ArtifactPostEmitMetadata::getUsedBindingRanges() { return Slice<ShaderBindingRange>(m_usedBindings.getBuffer(), m_usedBindings.getCount()); } diff --git a/source/compiler-core/slang-artifact-associated-impl.h b/source/compiler-core/slang-artifact-associated-impl.h index eef965e3e..415e01494 100644 --- a/source/compiler-core/slang-artifact-associated-impl.h +++ b/source/compiler-core/slang-artifact-associated-impl.h @@ -10,16 +10,24 @@ #include "slang-artifact-associated.h" +#include "slang-artifact-util.h" + +#include "slang-artifact-diagnostic-util.h" + namespace Slang { -class DiagnosticsImpl : public ComBaseObject, public IDiagnostics +class ArtifactDiagnostics : public ComBaseObject, public IArtifactDiagnostics { public: + typedef ArtifactDiagnostics ThisType; + SLANG_COM_BASE_IUNKNOWN_ALL // ICastable SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; + // IClonable + SLANG_NO_THROW virtual void* SLANG_MCALL clone(const Guid& intf) SLANG_OVERRIDE; // IDiagnostic SLANG_NO_THROW virtual const Diagnostic* SLANG_MCALL getAt(Index i) SLANG_OVERRIDE { return &m_diagnostics[i]; } SLANG_NO_THROW virtual Count SLANG_MCALL getCount() SLANG_OVERRIDE { return m_diagnostics.getCount(); } @@ -27,42 +35,42 @@ public: SLANG_NO_THROW virtual void SLANG_MCALL removeAt(Index i) SLANG_OVERRIDE { m_diagnostics.removeAt(i); } SLANG_NO_THROW virtual SlangResult SLANG_MCALL getResult() SLANG_OVERRIDE { return m_result; } SLANG_NO_THROW virtual void SLANG_MCALL setResult(SlangResult res) SLANG_OVERRIDE { m_result = res; } - SLANG_NO_THROW virtual void SLANG_MCALL setRaw(const ZeroTerminatedCharSlice& slice) SLANG_OVERRIDE; - SLANG_NO_THROW virtual ZeroTerminatedCharSlice SLANG_MCALL getRaw() SLANG_OVERRIDE { return m_raw; } + SLANG_NO_THROW virtual void SLANG_MCALL setRaw(const CharSlice& slice) SLANG_OVERRIDE; + SLANG_NO_THROW virtual void SLANG_MCALL appendRaw(const CharSlice& slice) SLANG_OVERRIDE; + SLANG_NO_THROW virtual TerminatedCharSlice SLANG_MCALL getRaw() SLANG_OVERRIDE { return CharSliceCaster::asTerminatedCharSlice(m_raw); } SLANG_NO_THROW virtual void SLANG_MCALL reset() SLANG_OVERRIDE; - SLANG_NO_THROW virtual Count SLANG_MCALL getCountAtLeastSeverity(Severity severity) SLANG_OVERRIDE; - SLANG_NO_THROW virtual Count SLANG_MCALL getCountBySeverity(Severity severity) SLANG_OVERRIDE; - SLANG_NO_THROW virtual bool SLANG_MCALL hasOfAtLeastSeverity(Severity severity) SLANG_OVERRIDE; - SLANG_NO_THROW virtual Count SLANG_MCALL getCountByStage(Stage stage, Count outCounts[Int(Severity::CountOf)]) SLANG_OVERRIDE; - SLANG_NO_THROW virtual void SLANG_MCALL removeBySeverity(Severity severity) SLANG_OVERRIDE; - SLANG_NO_THROW virtual void SLANG_MCALL maybeAddNote(const ZeroTerminatedCharSlice& in) SLANG_OVERRIDE; + SLANG_NO_THROW virtual Count SLANG_MCALL getCountAtLeastSeverity(Diagnostic::Severity severity) SLANG_OVERRIDE; + SLANG_NO_THROW virtual Count SLANG_MCALL getCountBySeverity(Diagnostic::Severity severity) SLANG_OVERRIDE; + SLANG_NO_THROW virtual bool SLANG_MCALL hasOfAtLeastSeverity(Diagnostic::Severity severity) SLANG_OVERRIDE; + SLANG_NO_THROW virtual Count SLANG_MCALL getCountByStage(Diagnostic::Stage stage, Count outCounts[Int(Diagnostic::Severity::CountOf)]) SLANG_OVERRIDE; + SLANG_NO_THROW virtual void SLANG_MCALL removeBySeverity(Diagnostic::Severity severity) SLANG_OVERRIDE; + SLANG_NO_THROW virtual void SLANG_MCALL maybeAddNote(const CharSlice& in) SLANG_OVERRIDE; SLANG_NO_THROW virtual void SLANG_MCALL requireErrorDiagnostic() SLANG_OVERRIDE; - SLANG_NO_THROW virtual void SLANG_MCALL appendSummary(ISlangBlob** outBlob) SLANG_OVERRIDE; - SLANG_NO_THROW virtual void SLANG_MCALL appendSimplifiedSummary(ISlangBlob** outBlob) SLANG_OVERRIDE; + SLANG_NO_THROW virtual void SLANG_MCALL calcSummary(ISlangBlob** outBlob) SLANG_OVERRIDE; + SLANG_NO_THROW virtual void SLANG_MCALL calcSimplifiedSummary(ISlangBlob** outBlob) SLANG_OVERRIDE; - DiagnosticsImpl(): - m_arena(1024) - { - } + /// Default ctor + ArtifactDiagnostics() {} + /// Copy ctor + ArtifactDiagnostics(const ThisType& rhs); + + /// Create + static ComPtr<IArtifactDiagnostics> create() { return ComPtr<IArtifactDiagnostics>(new ThisType); } protected: void* getInterface(const Guid& uuid); void* getObject(const Guid& uuid); - ZeroTerminatedCharSlice _allocateSlice(const Slice<char>& in); - - // We could consider storing paths, codes in StringSlicePool, but for now we just allocate all 'string type things' - // in the arena. - MemoryArena m_arena; + CharSliceAllocator m_allocator; List<Diagnostic> m_diagnostics; SlangResult m_result = SLANG_OK; // Raw diagnostics - ZeroTerminatedCharSlice m_raw; + StringBuilder m_raw; }; -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! PostEmitMetadataImpl !!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactPostEmitMetadata !!!!!!!!!!!!!!!!!!!!!!!!!! */ struct ShaderBindingRange { @@ -133,9 +141,11 @@ struct ShaderBindingRange } }; -class PostEmitMetadataImpl : public ComBaseObject, public IPostEmitMetadata +class ArtifactPostEmitMetadata : public ComBaseObject, public IArtifactPostEmitMetadata { public: + typedef ArtifactPostEmitMetadata ThisType; + SLANG_CLASS_GUID(0x6f82509f, 0xe48b, 0x4b83, { 0xa3, 0x84, 0x5d, 0x70, 0x83, 0x19, 0x83, 0xcc }) SLANG_COM_BASE_IUNKNOWN_ALL @@ -143,12 +153,14 @@ public: // ICastable SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - // IPostEmitMetadata + // IArtifactPostEmitMetadata SLANG_NO_THROW virtual Slice<ShaderBindingRange> SLANG_MCALL getUsedBindingRanges() SLANG_OVERRIDE; void* getInterface(const Guid& uuid); void* getObject(const Guid& uuid); + static ComPtr<IArtifactPostEmitMetadata> create() { return ComPtr<IArtifactPostEmitMetadata>(new ThisType); } + List<ShaderBindingRange> m_usedBindings; }; diff --git a/source/compiler-core/slang-artifact-associated.h b/source/compiler-core/slang-artifact-associated.h index e3dd83062..f63b8a673 100644 --- a/source/compiler-core/slang-artifact-associated.h +++ b/source/compiler-core/slang-artifact-associated.h @@ -7,15 +7,11 @@ namespace Slang { -/* Diagnostics. - -If there are raw diagnostics they can be associated to an artifact as (Kind::Text, Payload::Diagnostics) artifact */ -class IDiagnostics : public ICastable +struct ArtifactDiagnostic { -public: - SLANG_COM_INTERFACE(0x91f9b857, 0xcd6b, 0x45ca, { 0x8e, 0x3, 0x8f, 0xa3, 0x3c, 0x5c, 0xf0, 0x1a }); + typedef ArtifactDiagnostic ThisType; - enum class Severity + enum class Severity : uint8_t { Unknown, Info, @@ -23,7 +19,7 @@ public: Error, CountOf, }; - enum class Stage + enum class Stage : uint8_t { Compile, Link, @@ -31,19 +27,42 @@ public: struct Location { + typedef Location ThisType; + bool operator==(const ThisType& rhs) const { return line == rhs.line && column == rhs.column; } + bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } + Int line = 0; ///< One indexed line number. 0 if not defined Int column = 0; ///< One indexed *character (not byte)* column number. 0 if not defined }; - struct Diagnostic + bool operator==(const ThisType& rhs) const { - Severity severity = Severity::Unknown; ///< The severity of error - Stage stage = Stage::Compile; ///< The stage the error came from - ZeroTerminatedCharSlice text; ///< The text of the error - ZeroTerminatedCharSlice code; ///< The compiler specific error code - ZeroTerminatedCharSlice filePath; ///< The path the error originated from - Location location; - }; + return severity == rhs.severity && + stage == rhs.stage && + text == rhs.text && + code == rhs.code && + location == rhs.location; + } + bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } + + Severity severity = Severity::Unknown; ///< The severity of error + Stage stage = Stage::Compile; ///< The stage the error came from + TerminatedCharSlice text; ///< The text of the error + TerminatedCharSlice code; ///< The compiler specific error code + TerminatedCharSlice filePath; ///< The path the error originated from + Location location; ///< The location of the diagnostic in the filePath +}; + +/* Artifact diagnostics interface. + +IArtifactDiagnostics are added as associated types on an IArtifact typically. +*/ +class IArtifactDiagnostics : public IClonable +{ +public: + SLANG_COM_INTERFACE(0x91f9b857, 0xcd6b, 0x45ca, { 0x8e, 0x3, 0x8f, 0xa3, 0x3c, 0x5c, 0xf0, 0x1a }); + + typedef ArtifactDiagnostic Diagnostic; /// Get the diagnostic at the index SLANG_NO_THROW virtual const Diagnostic* SLANG_MCALL getAt(Index i) = 0; @@ -55,9 +74,11 @@ public: SLANG_NO_THROW virtual void SLANG_MCALL removeAt(Index i) = 0; /// Get raw diagnostics information - SLANG_NO_THROW virtual ZeroTerminatedCharSlice SLANG_MCALL getRaw() = 0; + SLANG_NO_THROW virtual TerminatedCharSlice SLANG_MCALL getRaw() = 0; /// Set the raw diagnostic info - SLANG_NO_THROW virtual void SLANG_MCALL setRaw(const ZeroTerminatedCharSlice& slice) = 0; + SLANG_NO_THROW virtual void SLANG_MCALL setRaw(const CharSlice& slice) = 0; + /// Append to the raw diagnostic + SLANG_NO_THROW virtual void SLANG_MCALL appendRaw(const CharSlice& slice) = 0; /// Get the result for a compilation SLANG_NO_THROW virtual SlangResult SLANG_MCALL getResult() = 0; @@ -68,35 +89,35 @@ public: SLANG_NO_THROW virtual void SLANG_MCALL reset() = 0; /// Count the number of diagnostics which have 'severity' or greater - SLANG_NO_THROW virtual Count SLANG_MCALL getCountAtLeastSeverity(Severity severity) = 0; + SLANG_NO_THROW virtual Count SLANG_MCALL getCountAtLeastSeverity(Diagnostic::Severity severity) = 0; /// Get the number of diagnostics by severity - SLANG_NO_THROW virtual Count SLANG_MCALL getCountBySeverity(Severity severity) = 0; + SLANG_NO_THROW virtual Count SLANG_MCALL getCountBySeverity(Diagnostic::Severity severity) = 0; /// True if there are any diagnostics of severity or worse - SLANG_NO_THROW virtual bool SLANG_MCALL hasOfAtLeastSeverity(Severity severity) = 0; + SLANG_NO_THROW virtual bool SLANG_MCALL hasOfAtLeastSeverity(Diagnostic::Severity severity) = 0; /// Stores in outCounts, the amount of diagnostics for the stage of each severity - SLANG_NO_THROW virtual Count SLANG_MCALL getCountByStage(Stage stage, Count outCounts[Int(Severity::CountOf)]) = 0; + SLANG_NO_THROW virtual Count SLANG_MCALL getCountByStage(Diagnostic::Stage stage, Count outCounts[Int(Diagnostic::Severity::CountOf)]) = 0; /// Remove all diagnostics of the type - SLANG_NO_THROW virtual void SLANG_MCALL removeBySeverity(Severity severity) = 0; + SLANG_NO_THROW virtual void SLANG_MCALL removeBySeverity(Diagnostic::Severity severity) = 0; /// Add a note - SLANG_NO_THROW virtual void SLANG_MCALL maybeAddNote(const ZeroTerminatedCharSlice& in) = 0; + SLANG_NO_THROW virtual void SLANG_MCALL maybeAddNote(const CharSlice& in) = 0; /// If there are no error diagnostics, adds a generic error diagnostic SLANG_NO_THROW virtual void SLANG_MCALL requireErrorDiagnostic() = 0; - /// Append a summary to out - SLANG_NO_THROW virtual void SLANG_MCALL appendSummary(ISlangBlob** outBlob) = 0; - /// Appends a summary that just identifies if there is an error of a type (not a count) - SLANG_NO_THROW virtual void SLANG_MCALL appendSimplifiedSummary(ISlangBlob** outBlob) = 0; + /// Creates summary text and place in outBlob + SLANG_NO_THROW virtual void SLANG_MCALL calcSummary(ISlangBlob** outBlob) = 0; + /// Creates a simplified summary text and places it in out blob + SLANG_NO_THROW virtual void SLANG_MCALL calcSimplifiedSummary(ISlangBlob** outBlob) = 0; }; struct ShaderBindingRange; -class IPostEmitMetadata : public ICastable +class IArtifactPostEmitMetadata : public ICastable { public: SLANG_COM_INTERFACE(0x5d03bce9, 0xafb1, 0x4fc8, { 0xa4, 0x6f, 0x3c, 0xe0, 0x7b, 0x6, 0x1b, 0x1b }); diff --git a/source/compiler-core/slang-artifact-diagnostic-util.cpp b/source/compiler-core/slang-artifact-diagnostic-util.cpp new file mode 100644 index 000000000..0f6b70ab4 --- /dev/null +++ b/source/compiler-core/slang-artifact-diagnostic-util.cpp @@ -0,0 +1,158 @@ +// slang-artifact-diagnostic-util.cpp +#include "slang-artifact-diagnostic-util.h" + +#include "../core/slang-char-util.h" +#include "../core/slang-string-util.h" + +namespace Slang { + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CharSliceAllocator !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +TerminatedCharSlice CharSliceAllocator::allocate(const char* in) +{ + const size_t length = ::strlen(in); + auto dst = m_arena.allocateString(in, length); + return TerminatedCharSlice(dst, length); +} + +TerminatedCharSlice CharSliceAllocator::allocate(const UnownedStringSlice& slice) +{ + const auto length = slice.getLength(); + auto dst = m_arena.allocateString(slice.begin(), length); + return TerminatedCharSlice(dst, length); +} + +TerminatedCharSlice CharSliceAllocator::allocate(const Slice<char>& slice) +{ + const auto count = slice.count; + auto dst = m_arena.allocateString(slice.begin(), count); + return TerminatedCharSlice(dst, count); +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDiagnosticsUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +/* static */UnownedStringSlice ArtifactDiagnosticUtil::getSeverityText(Severity severity) +{ + switch (severity) + { + default: return UnownedStringSlice::fromLiteral("Unknown"); + case Severity::Info: return UnownedStringSlice::fromLiteral("Info"); + case Severity::Warning: return UnownedStringSlice::fromLiteral("Warning"); + case Severity::Error: return UnownedStringSlice::fromLiteral("Error"); + } +} + +/* static */SlangResult ArtifactDiagnosticUtil::splitPathLocation(CharSliceAllocator& allocator, const UnownedStringSlice& pathLocation, ArtifactDiagnostic& outDiagnostic) +{ + const Index lineStartIndex = pathLocation.lastIndexOf('('); + if (lineStartIndex >= 0) + { + outDiagnostic.filePath = allocator.allocate(pathLocation.head(lineStartIndex).trim()); + + const UnownedStringSlice tail = pathLocation.tail(lineStartIndex + 1); + const Index lineEndIndex = tail.indexOf(')'); + + if (lineEndIndex >= 0) + { + // Extract the location info + UnownedStringSlice locationSlice(tail.begin(), tail.begin() + lineEndIndex); + + UnownedStringSlice slices[2]; + const Index numSlices = StringUtil::split(locationSlice, ',', 2, slices); + + // NOTE! FXC actually outputs a range of columns in the form of START-END in the column position + // We don't need to parse here, because we only care about the line number + + Int lineNumber = 0; + if (numSlices > 0) + { + SLANG_RETURN_ON_FAIL(StringUtil::parseInt(slices[0], lineNumber)); + } + + // Store the line + outDiagnostic.location.line = lineNumber; + } + } + else + { + outDiagnostic.filePath = allocator.allocate(pathLocation); + } + return SLANG_OK; +} + +/* static */SlangResult ArtifactDiagnosticUtil::splitColonDelimitedLine(const UnownedStringSlice& line, Int pathIndex, List<UnownedStringSlice>& outSlices) +{ + StringUtil::split(line, ':', outSlices); + + // Now we want to fix up a path as might have drive letter, and therefore : + // If this is the situation then we need to have a slice after the one at the index + if (outSlices.getCount() > pathIndex + 1) + { + const UnownedStringSlice pathStart = outSlices[pathIndex].trim(); + if (pathStart.getLength() == 1 && CharUtil::isAlpha(pathStart[0])) + { + // Splice back together + outSlices[pathIndex] = UnownedStringSlice(outSlices[pathIndex].begin(), outSlices[pathIndex + 1].end()); + outSlices.removeAt(pathIndex + 1); + } + } + + return SLANG_OK; +} + +/* static */SlangResult ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics(CharSliceAllocator& allocator, const UnownedStringSlice& inText, Int pathIndex, LineParser lineParser, IArtifactDiagnostics* diagnostics) +{ + List<UnownedStringSlice> splitLine; + + UnownedStringSlice text(inText), line; + while (StringUtil::extractLine(text, line)) + { + SLANG_RETURN_ON_FAIL(splitColonDelimitedLine(line, pathIndex, splitLine)); + + ArtifactDiagnostic diagnostic; + diagnostic.severity = Severity::Error; + diagnostic.stage = ArtifactDiagnostic::Stage::Compile; + diagnostic.location.line = 0; + diagnostic.location.column = 0; + + if (SLANG_SUCCEEDED(lineParser(allocator, line, splitLine, diagnostic))) + { + diagnostics->add(diagnostic); + } + else + { + // If couldn't parse, just add as a note + maybeAddNote(line, diagnostics); + } + } + + return SLANG_OK; +} + +/* static */void ArtifactDiagnosticUtil::maybeAddNote(const UnownedStringSlice& in, IArtifactDiagnostics* diagnostics) +{ + // Don't bother adding an empty line + if (in.trim().getLength() == 0) + { + return; + } + + // If there's nothing previous, we'll ignore too, as note should be in addition to + // a pre-existing error/warning + if (diagnostics->getCount() == 0) + { + return; + } + + // Make it a note on the output + ArtifactDiagnostic diagnostic; + + String text(in); + + diagnostic.severity = ArtifactDiagnostic::Severity::Info; + diagnostic.text = CharSliceCaster::asTerminatedCharSlice(text); + diagnostics->add(diagnostic); +} + + +} // namespace Slang diff --git a/source/compiler-core/slang-artifact-diagnostic-util.h b/source/compiler-core/slang-artifact-diagnostic-util.h new file mode 100644 index 000000000..5a98acd22 --- /dev/null +++ b/source/compiler-core/slang-artifact-diagnostic-util.h @@ -0,0 +1,87 @@ +// slang-artifact-diagnostic-util.h +#ifndef SLANG_ARTIFACT_DIAGNOSTIC_UTIL_H +#define SLANG_ARTIFACT_DIAGNOSTIC_UTIL_H + +#include "slang-artifact.h" + +#include "slang-artifact-associated.h" + +#include "../core/slang-memory-arena.h" + +namespace Slang +{ + +/* +The reason to wrap in a struct rathan than have as free functions is doing so will lead to compile time +errors with incorrect usage around temporarires. +*/ +struct CharSliceCaster +{ + /// The slice will only be in scope whilst the string is + static TerminatedCharSlice asTerminatedCharSlice(const String& in) { auto unowned = in.getUnownedSlice(); return TerminatedCharSlice(unowned.begin(), unowned.getLength()); } + + static CharSlice asCharSlice(const String& in) { auto unowned = in.getUnownedSlice(); return CharSlice(unowned.begin(), unowned.getLength()); } + +private: + // We don't want temporaries to be 'asSliced' so disable + static TerminatedCharSlice asTerminatedCharSlice(const String&& in) = delete; + static CharSlice asCharSlice(const String&& in) = delete; +}; + +SLANG_FORCE_INLINE UnownedStringSlice asStringSlice(const CharSlice& slice) +{ + return UnownedStringSlice(slice.begin(), slice.end()); +} + +SLANG_FORCE_INLINE CharSlice asCharSlice(const UnownedStringSlice& slice) +{ + return CharSlice(slice.begin(), slice.getLength()); +} + +struct CharSliceAllocator +{ + TerminatedCharSlice allocate(const Slice<char>& slice); + TerminatedCharSlice allocate(const UnownedStringSlice& slice); + TerminatedCharSlice allocate(const String& in) { return allocate(in.getUnownedSlice()); } + TerminatedCharSlice allocate(const char* in); + TerminatedCharSlice allocate(const char* start, const char* end) { return allocate(UnownedStringSlice(start, end)); } + + void deallocateAll() { m_arena.deallocateAll(); } + + CharSliceAllocator(): + m_arena(1024) + { + } +protected: + + MemoryArena m_arena; +}; + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDiagnosticUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +struct ArtifactDiagnosticUtil +{ + typedef ArtifactDiagnostic::Severity Severity; + + /// Given severity return as text + static UnownedStringSlice getSeverityText(Severity severity); + + /// Given a path, that holds line number and potentially column number in () after path, writes result into outDiagnostic + static SlangResult splitPathLocation(CharSliceAllocator& allocator, const UnownedStringSlice& pathLocation, ArtifactDiagnostic& outDiagnostic); + + /// Split the line (separated by :), where a path is at pathIndex + static SlangResult splitColonDelimitedLine(const UnownedStringSlice& line, Int pathIndex, List<UnownedStringSlice>& outSlices); + + typedef SlangResult(*LineParser)(CharSliceAllocator& allocator, const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, ArtifactDiagnostic& outDiagnostic); + + /// Given diagnostics in inText that are colon delimited, use lineParser to do per line parsing. + static SlangResult parseColonDelimitedDiagnostics(CharSliceAllocator& allocator, const UnownedStringSlice& inText, Int pathIndex, LineParser lineParser, IArtifactDiagnostics* diagnostics); + + /// Maybe add a note + static void maybeAddNote(const UnownedStringSlice& in, IArtifactDiagnostics* diagnostics); +}; + + +} // namespace Slang + +#endif diff --git a/source/compiler-core/slang-artifact-handler-impl.cpp b/source/compiler-core/slang-artifact-handler-impl.cpp index c342becec..028fa1bb9 100644 --- a/source/compiler-core/slang-artifact-handler-impl.cpp +++ b/source/compiler-core/slang-artifact-handler-impl.cpp @@ -14,9 +14,6 @@ #include "../core/slang-io.h" #include "../core/slang-shared-library.h" -// For workaround for DownstreamResult -#include "slang-downstream-dep1.h" - namespace Slang { /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! DefaultArtifactHandler !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -129,24 +126,6 @@ SlangResult DefaultArtifactHandler::getOrCreateRepresentation(IArtifact* artifac } } - // TODO(JS): Temporary whilst DownstreamCompileResult is - // Special handling for DownstreamCompileResult - if (auto downstreamResult = findRepresentation<DownstreamCompileResult>(artifact)) - { - if (guid == ISlangBlob::getTypeGuid()) - { - ComPtr<ISlangBlob> blob; - SLANG_RETURN_ON_FAIL(downstreamResult->getBinary(blob)); - return _addRepresentation(artifact, keep, blob, outCastable); - } - else if (guid == ISlangSharedLibrary::getTypeGuid()) - { - ComPtr<ISlangSharedLibrary> lib; - SLANG_RETURN_ON_FAIL(DownstreamUtil_Dep1::getDownstreamSharedLibrary(downstreamResult, lib)); - return _addRepresentation(artifact, keep, lib, outCastable); - } - } - // We can ask each representation if they can do the conversion to the type, if they can we just use that for (ICastable* castable : reps) { diff --git a/source/compiler-core/slang-artifact-util.cpp b/source/compiler-core/slang-artifact-util.cpp index fb3157522..a09454998 100644 --- a/source/compiler-core/slang-artifact-util.cpp +++ b/source/compiler-core/slang-artifact-util.cpp @@ -12,6 +12,8 @@ namespace Slang { +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + /* static */ComPtr<IArtifactContainer> ArtifactUtil::createContainer(const ArtifactDesc& desc) { const auto containerDesc = ArtifactDesc::make(ArtifactKind::Container, ArtifactPayload::CompileResults, desc.style); diff --git a/source/compiler-core/slang-artifact-util.h b/source/compiler-core/slang-artifact-util.h index c4768a7b8..dc370b557 100644 --- a/source/compiler-core/slang-artifact-util.h +++ b/source/compiler-core/slang-artifact-util.h @@ -10,7 +10,6 @@ namespace Slang struct ArtifactUtil { - /// Get the base name of this artifact. /// If there is a path set, will extract the name from that (stripping prefix, extension as necessary). /// Else if there is an explicit name set, this is returned. diff --git a/source/compiler-core/slang-artifact.h b/source/compiler-core/slang-artifact.h index c54282c09..ee5f6b61d 100644 --- a/source/compiler-core/slang-artifact.h +++ b/source/compiler-core/slang-artifact.h @@ -9,7 +9,6 @@ namespace Slang { - /* Simplest slice types. We can't use UnownedStringSlice etc, because they implement functionality in libraries, and we want to use these types in headers. If we wanted a C implementation it would be easy to use a macro to generate the functionality */ @@ -30,12 +29,30 @@ struct Slice Count count; }; -struct ZeroTerminatedCharSlice : Slice<char> +struct CharSlice : public Slice<char> { + typedef CharSlice ThisType; typedef Slice<char> Super; - explicit ZeroTerminatedCharSlice(const char* in) :Super(in, ::strlen(in)) {} - ZeroTerminatedCharSlice(const char* in, Count inCount) :Super(in, inCount) { SLANG_ASSERT(in[inCount] == 0); } - ZeroTerminatedCharSlice() :Super("", 0) {} + + bool operator==(const ThisType& rhs) const { return count == rhs.count && (data == rhs.data || ::memcmp(data, rhs.data, count) == 0); } + bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } + + explicit CharSlice(const char* in) :Super(in, ::strlen(in)) {} + CharSlice(const char* in, Count inCount) :Super(in, inCount) {} + CharSlice() :Super(nullptr, 0) {} +}; + +struct TerminatedCharSlice : public CharSlice +{ + typedef TerminatedCharSlice ThisType; + typedef CharSlice Super; + + SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const { return Super::operator==(rhs); } + SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } + + explicit TerminatedCharSlice(const char* in) :Super(in) {} + TerminatedCharSlice(const char* in, Count inCount) :Super(in, inCount) { SLANG_ASSERT(in[inCount] == 0); } + TerminatedCharSlice() :Super("", 0) {} }; /* As a rule of thumb, if we can define some aspect in a hierarchy then we should do so at the highest level. @@ -386,6 +403,15 @@ public: virtual SLANG_NO_THROW IArtifact* SLANG_MCALL findArtifactByDesc(FindStyle findStyle, const ArtifactDesc& desc) = 0; }; +/* Interface for an artifact that *contain* a hierarchy of other child artifacts. + +Containment is a different concept to *association*. An association can hold any interface, and associations are for +objects that are associated with an artifact - like diagnostics or meta data. Children artifacts can build up hierarchies +and the children can be thought to be contained by the artifact they are a child of. + +The IArtifactContainer interface exists additionally to provide some type safety, and make it clear +in code where a container or just 'an artifact' is required. +*/ class IArtifactContainer : public IArtifact { public: diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index 64ad7fbc9..4f7462901 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -12,108 +12,13 @@ #include "../core/slang-blob.h" #include "../core/slang-char-util.h" +#include "../core/slang-castable-list-impl.h" -namespace Slang -{ - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamDiagnostic !!!!!!!!!!!!!!!!!!!!!!!!*/ - -/* static */UnownedStringSlice DownstreamDiagnostic::getSeverityText(Severity severity) -{ - switch (severity) - { - default: return UnownedStringSlice::fromLiteral("Unknown"); - case Severity::Info: return UnownedStringSlice::fromLiteral("Info"); - case Severity::Warning: return UnownedStringSlice::fromLiteral("Warning"); - case Severity::Error: return UnownedStringSlice::fromLiteral("Error"); - } -} - -/* static */SlangResult DownstreamDiagnostic::splitPathLocation(const UnownedStringSlice& pathLocation, DownstreamDiagnostic& outDiagnostic) -{ - const Index lineStartIndex = pathLocation.lastIndexOf('('); - if (lineStartIndex >= 0) - { - outDiagnostic.filePath = UnownedStringSlice(pathLocation.head(lineStartIndex).trim()); - - const UnownedStringSlice tail = pathLocation.tail(lineStartIndex + 1); - const Index lineEndIndex = tail.indexOf(')'); - - if (lineEndIndex >= 0) - { - // Extract the location info - UnownedStringSlice locationSlice(tail.begin(), tail.begin() + lineEndIndex); - - UnownedStringSlice slices[2]; - const Index numSlices = StringUtil::split(locationSlice, ',', 2, slices); - - // NOTE! FXC actually outputs a range of columns in the form of START-END in the column position - // We don't need to parse here, because we only care about the line number - - Int lineNumber = 0; - if (numSlices > 0) - { - SLANG_RETURN_ON_FAIL(StringUtil::parseInt(slices[0], lineNumber)); - } - - // Store the line - outDiagnostic.fileLine = lineNumber; - } - } - else - { - outDiagnostic.filePath = pathLocation; - } - return SLANG_OK; -} - -/* static */SlangResult DownstreamDiagnostic::splitColonDelimitedLine(const UnownedStringSlice& line, Int pathIndex, List<UnownedStringSlice>& outSlices) -{ - StringUtil::split(line, ':', outSlices); - - // Now we want to fix up a path as might have drive letter, and therefore : - // If this is the situation then we need to have a slice after the one at the index - if (outSlices.getCount() > pathIndex + 1) - { - const UnownedStringSlice pathStart = outSlices[pathIndex].trim(); - if (pathStart.getLength() == 1 && CharUtil::isAlpha(pathStart[0])) - { - // Splice back together - outSlices[pathIndex] = UnownedStringSlice(outSlices[pathIndex].begin(), outSlices[pathIndex + 1].end()); - outSlices.removeAt(pathIndex + 1); - } - } - - return SLANG_OK; -} +#include "slang-artifact-associated-impl.h" +#include "slang-artifact-util.h" -/* static */SlangResult DownstreamDiagnostic::parseColonDelimitedDiagnostics(const UnownedStringSlice& inText, Int pathIndex, LineParser lineParser, List<DownstreamDiagnostic>& outDiagnostics) +namespace Slang { - List<UnownedStringSlice> splitLine; - - UnownedStringSlice text(inText), line; - while (StringUtil::extractLine(text, line)) - { - SLANG_RETURN_ON_FAIL(splitColonDelimitedLine(line, pathIndex, splitLine)); - - DownstreamDiagnostic diagnostic; - diagnostic.severity = DownstreamDiagnostic::Severity::Error; - diagnostic.stage = DownstreamDiagnostic::Stage::Compile; - diagnostic.fileLine = 0; - - if (SLANG_SUCCEEDED(lineParser(line, splitLine, diagnostic))) - { - outDiagnostics.add(diagnostic); - } - else - { - // If couldn't parse, just add as a note - DownstreamDiagnostics::addNote(line, outDiagnostics); - } - } - - return SLANG_OK; -} /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompilerBase !!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ @@ -154,211 +59,75 @@ void* DownstreamCompilerBase::getObject(const Guid& guid) return nullptr; } -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamDiagnostics !!!!!!!!!!!!!!!!!!!!!!*/ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!*/ -Index DownstreamDiagnostics::getCountAtLeastSeverity(Diagnostic::Severity severity) const +void* CommandLineDownstreamArtifactRepresentation::castAs(const Guid& guid) { - Index count = 0; - for (const auto& msg : diagnostics) - { - count += Index(Index(msg.severity) >= Index(severity)); - } - return count; -} - -Index DownstreamDiagnostics::getCountBySeverity(Diagnostic::Severity severity) const -{ - Index count = 0; - for (const auto& msg : diagnostics) + if (auto ptr = getInterface(guid)) { - count += Index(msg.severity == severity); + return ptr; } - return count; + return getObject(guid); } -void DownstreamDiagnostics::requireErrorDiagnostic() +void* CommandLineDownstreamArtifactRepresentation::getInterface(const Guid& guid) { - // If we find an error, we don't need to add a generic diagnostic - for (const auto& msg : diagnostics) + if (guid == ISlangUnknown::getTypeGuid() || + guid == ICastable::getTypeGuid() || + guid == IArtifactRepresentation::getTypeGuid()) { - if (Index(msg.severity) >= Index(DownstreamDiagnostic::Severity::Error)) - { - return; - } + IArtifactRepresentation* rep = this; + return rep; } - DownstreamDiagnostic diagnostic; - diagnostic.reset(); - diagnostic.severity = DownstreamDiagnostic::Severity::Error; - diagnostic.text = rawDiagnostics; - - // Add the diagnostic - diagnostics.add(diagnostic); -} - -Int DownstreamDiagnostics::countByStage(Diagnostic::Stage stage, Index counts[Int(Diagnostic::Severity::CountOf)]) const -{ - Int count = 0; - ::memset(counts, 0, sizeof(Index) * Int(Diagnostic::Severity::CountOf)); - for (const auto& diagnostic : diagnostics) - { - if (diagnostic.stage == stage) - { - count++; - counts[Index(diagnostic.severity)]++; - } - } - return count++; + return nullptr; } -static void _appendCounts(const Index counts[Int(DownstreamDiagnostic::Severity::CountOf)], StringBuilder& out) +void* CommandLineDownstreamArtifactRepresentation::getObject(const Guid& guid) { - typedef DownstreamDiagnostic::Severity Severity; - - for (Index i = 0; i < Int(Severity::CountOf); i++) - { - if (counts[i] > 0) - { - out << DownstreamDiagnostic::getSeverityText(Severity(i)) << "(" << counts[i] << ") "; - } - } + SLANG_UNUSED(guid); + return nullptr; } -static void _appendSimplified(const Index counts[Int(DownstreamDiagnostic::Severity::CountOf)], StringBuilder& out) +SlangResult CommandLineDownstreamArtifactRepresentation::createRepresentation(const Guid& typeGuid, ICastable** outCastable) { - typedef DownstreamDiagnostic::Severity Severity; - for (Index i = 0; i < Int(Severity::CountOf); i++) + if (typeGuid == ISlangSharedLibrary::getTypeGuid()) { - if (counts[i] > 0) + // Okay we want to load + // Try loading the shared library + SharedLibrary::Handle handle; + if (SLANG_FAILED(SharedLibrary::loadWithPlatformPath(m_moduleFilePath.getBuffer(), handle))) { - out << DownstreamDiagnostic::getSeverityText(Severity(i)) << " "; + return SLANG_FAIL; } - } -} -void DownstreamDiagnostics::appendSummary(StringBuilder& out) const -{ - Index counts[Int(Diagnostic::Severity::CountOf)]; - if (countByStage(Diagnostic::Stage::Compile, counts) > 0) - { - out << "Compile: "; - _appendCounts(counts, out); - out << "\n"; - } - if (countByStage(Diagnostic::Stage::Link, counts) > 0) - { - out << "Link: "; - _appendCounts(counts, out); - out << "\n"; - } -} - -void DownstreamDiagnostics::appendSimplifiedSummary(StringBuilder& out) const -{ - Index counts[Int(Diagnostic::Severity::CountOf)]; - if (countByStage(Diagnostic::Stage::Compile, counts) > 0) - { - out << "Compile: "; - _appendSimplified(counts, out); - out << "\n"; - } - if (countByStage(Diagnostic::Stage::Link, counts) > 0) - { - out << "Link: "; - _appendSimplified(counts, out); - out << "\n"; - } -} + // The shared library needs to keep temp files in scope + auto temporarySharedLibrary = new TemporarySharedLibrary(handle, m_moduleFilePath); + ComPtr<ISlangSharedLibrary> lib(temporarySharedLibrary); -void DownstreamDiagnostics::removeBySeverity(Diagnostic::Severity severity) -{ - Index count = diagnostics.getCount(); - for (Index i = 0; i < count; ++i) - { - if (diagnostics[i].severity == severity) - { - diagnostics.removeAt(i); - i--; - count--; - } - } -} + // Set any additional info on the non COM pointer + temporarySharedLibrary->m_temporaryFileSet = m_temporaryFiles; -/* static */void DownstreamDiagnostics::addNote(const UnownedStringSlice& in, List<DownstreamDiagnostic>& ioDiagnostics) -{ - // Don't bother adding an empty line - if (in.trim().getLength() == 0) - { - return; + *outCastable = lib.detach(); + return SLANG_OK; } - - // If there's nothing previous, we'll ignore too, as note should be in addition to - // a pre-existing error/warning - if (ioDiagnostics.getCount() == 0) + else if (typeGuid == ISlangBlob::getTypeGuid()) { - return; - } - - // Make it a note on the output - DownstreamDiagnostic diagnostic; - diagnostic.reset(); - diagnostic.severity = DownstreamDiagnostic::Severity::Info; - diagnostic.text = in; - ioDiagnostics.add(diagnostic); -} - -void DownstreamDiagnostics::addNote(const UnownedStringSlice& in) -{ - addNote(in, diagnostics); -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamCompileResult !!!!!!!!!!!!!!!!!!!!!!*/ + List<uint8_t> contents; + // Read the binary + // Read the contents of the binary + SLANG_RETURN_ON_FAIL(File::readAllBytes(m_moduleFilePath, contents)); -SlangResult CommandLineDownstreamCompileResult::getHostCallableSharedLibrary(ComPtr<ISlangSharedLibrary>& outLibrary) -{ - if (m_hostCallableSharedLibrary) - { - outLibrary = m_hostCallableSharedLibrary; + *outCastable = CastableUtil::getCastable(ScopeRefObjectBlob::create(ListBlob::moveCreate(contents), m_temporaryFiles).detach()).detach(); return SLANG_OK; } - // Okay we want to load - // Try loading the shared library - SharedLibrary::Handle handle; - if (SLANG_FAILED(SharedLibrary::loadWithPlatformPath(m_moduleFilePath.getBuffer(), handle))) - { - return SLANG_FAIL; - } - - { - // The shared library needs to keep temp files in scope - auto temporarySharedLibrary = new TemporarySharedLibrary(handle, m_moduleFilePath); - // Make sure it gets a ref count - m_hostCallableSharedLibrary = temporarySharedLibrary; - // Set any additional info on the non COM pointer - temporarySharedLibrary->m_temporaryFileSet = m_temporaryFiles; - } - - outLibrary = m_hostCallableSharedLibrary; - return SLANG_OK; + return SLANG_E_NOT_AVAILABLE; } -SlangResult CommandLineDownstreamCompileResult::getBinary(ComPtr<ISlangBlob>& outBlob) +bool CommandLineDownstreamArtifactRepresentation::exists() { - if (m_binaryBlob) - { - outBlob = m_binaryBlob; - return SLANG_OK; - } - - List<uint8_t> contents; - // Read the binary - // Read the contents of the binary - SLANG_RETURN_ON_FAIL(File::readAllBytes(m_moduleFilePath, contents)); - - m_binaryBlob = ScopeRefObjectBlob::create(ListBlob::moveCreate(contents), m_temporaryFiles); - outBlob = m_binaryBlob; - return SLANG_OK; + return File::exists(m_moduleFilePath); } /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamCompiler !!!!!!!!!!!!!!!!!!!!!!*/ @@ -392,7 +161,7 @@ static bool _isContentsInFile(const DownstreamCompileOptions& options) return false; } -SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptions, RefPtr<DownstreamCompileResult>& out) +SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptions, IArtifact** outArtifact) { // Copy the command line options CommandLine cmdLine(m_cmdLine); @@ -402,7 +171,6 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio // Find all the files that will be produced RefPtr<TemporaryFileSet> productFileSet(new TemporaryFileSet); - if (options.modulePath.getLength() == 0 || options.sourceContents.getLength() != 0) { String modulePath = options.modulePath; @@ -491,10 +259,19 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio } #endif - DownstreamDiagnostics diagnostics; + auto artifact = ArtifactUtil::createArtifactForCompileTarget(options.targetType); + + auto diagnostics = ArtifactDiagnostics::create(); + SLANG_RETURN_ON_FAIL(parseOutput(exeRes, diagnostics)); - out = new CommandLineDownstreamCompileResult(diagnostics, moduleFilePath, productFileSet); + // Add the artifact + artifact->addAssociated(diagnostics); + + ComPtr<IArtifactRepresentation> rep(new CommandLineDownstreamArtifactRepresentation(moduleFilePath, productFileSet)); + artifact->addRepresentation(rep); + + *outArtifact = artifact.detach(); return SLANG_OK; } diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h index ece6c1c51..997a2b099 100644 --- a/source/compiler-core/slang-downstream-compiler.h +++ b/source/compiler-core/slang-downstream-compiler.h @@ -14,147 +14,13 @@ #include "../../slang-com-ptr.h" #include "slang-artifact.h" +#include "slang-artifact-associated.h" namespace Slang { struct SourceManager; -struct DownstreamDiagnostic -{ - typedef DownstreamDiagnostic ThisType; - - enum class Severity - { - Unknown, - Info, - Warning, - Error, - CountOf, - }; - enum class Stage - { - Compile, - Link, - }; - - void reset() - { - severity = Severity::Unknown; - stage = Stage::Compile; - fileLine = 0; - } - - bool operator==(const ThisType& rhs) const - { - return severity == rhs.severity && - stage == rhs.stage && - text == rhs.text && - code == rhs.code && - filePath == rhs.filePath && - fileLine == rhs.fileLine; - } - bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - - static UnownedStringSlice getSeverityText(Severity severity); - - /// Given a path, that holds line number and potentially column number in () after path, writes result into outDiagnostic - static SlangResult splitPathLocation(const UnownedStringSlice& pathLocation, DownstreamDiagnostic& outDiagnostic); - - /// Split the line (separated by :), where a path is at pathIndex - static SlangResult splitColonDelimitedLine(const UnownedStringSlice& line, Int pathIndex, List<UnownedStringSlice>& outSlices); - - typedef SlangResult (*LineParser)(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic); - - /// Given diagnostics in inText that are colon delimited, use lineParser to do per line parsing. - static SlangResult parseColonDelimitedDiagnostics(const UnownedStringSlice& inText, Int pathIndex, LineParser lineParser, List<DownstreamDiagnostic>& outDiagnostics); - - Severity severity = Severity::Unknown; ///< The severity of error - Stage stage = Stage::Compile; ///< The stage the error came from - String text; ///< The text of the error - String code; ///< The compiler specific error code - String filePath; ///< The path the error originated from - Int fileLine = 0; ///< The line number the error came from -}; - -struct DownstreamDiagnostics -{ - typedef DownstreamDiagnostic Diagnostic; - - /// Reset to an initial empty state - void reset() { diagnostics.clear(); rawDiagnostics = String(); result = SLANG_OK; } - - /// Count the number of diagnostics which have 'severity' or greater - Index getCountAtLeastSeverity(Diagnostic::Severity severity) const; - - /// Get the number of diagnostics by severity - Index getCountBySeverity(Diagnostic::Severity severity) const; - /// True if there are any diagnostics of severity - bool has(Diagnostic::Severity severity) const { return getCountBySeverity(severity) > 0; } - - /// Stores in outCounts, the amount of diagnostics for the stage of each severity - Int countByStage(Diagnostic::Stage stage, Index outCounts[Int(Diagnostic::Severity::CountOf)]) const; - - /// Append a summary to out - void appendSummary(StringBuilder& out) const; - /// Appends a summary that just identifies if there is an error of a type (not a count) - void appendSimplifiedSummary(StringBuilder& out) const; - - /// Remove all diagnostics of the type - void removeBySeverity(Diagnostic::Severity severity); - - /// Add a note - void addNote(const UnownedStringSlice& in); - - /// If there are no error diagnostics, adds a generic error diagnostic - void requireErrorDiagnostic(); - - static void addNote(const UnownedStringSlice& in, List<DownstreamDiagnostic>& ioDiagnostics); - - String rawDiagnostics; - - SlangResult result = SLANG_OK; - List<Diagnostic> diagnostics; -}; - -class DownstreamCompileResult : public RefObject -{ -public: - SLANG_CLASS_GUID(0xdfc5d318, 0x8675, 0x40ef, { 0xbd, 0x7b, 0x4, 0xa4, 0xff, 0x66, 0x11, 0x30 }) - - virtual SlangResult getHostCallableSharedLibrary(ComPtr<ISlangSharedLibrary>& outLibrary) = 0; - virtual SlangResult getBinary(ComPtr<ISlangBlob>& outBlob) = 0; - - const DownstreamDiagnostics& getDiagnostics() const { return m_diagnostics; } - - /// Ctor - DownstreamCompileResult(const DownstreamDiagnostics& diagnostics): - m_diagnostics(diagnostics) - {} - -protected: - DownstreamDiagnostics m_diagnostics; -}; - - -class BlobDownstreamCompileResult : public DownstreamCompileResult -{ -public: - typedef DownstreamCompileResult Super; - - virtual SlangResult getHostCallableSharedLibrary(ComPtr<ISlangSharedLibrary>& outLibrary) SLANG_OVERRIDE { SLANG_UNUSED(outLibrary); return SLANG_FAIL; } - virtual SlangResult getBinary(ComPtr<ISlangBlob>& outBlob) SLANG_OVERRIDE { outBlob = m_blob; return m_blob ? SLANG_OK : SLANG_FAIL; } - - BlobDownstreamCompileResult(const DownstreamDiagnostics& diags, ISlangBlob* blob): - Super(diags), - m_blob(blob) - { - - } -protected: - ComPtr<ISlangBlob> m_blob; -}; - // Compiler description struct DownstreamCompilerDesc { @@ -320,8 +186,7 @@ public: typedef DownstreamCompilerDesc Desc; typedef DownstreamCompileOptions CompileOptions; - typedef DownstreamCompileResult CompileResult; - + typedef CompileOptions::OptimizationLevel OptimizationLevel; typedef CompileOptions::DebugInfoType DebugInfoType; typedef CompileOptions::FloatingPointMode FloatingPointMode; @@ -332,7 +197,7 @@ public: /// Get the desc of this compiler virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() = 0; /// Compile using the specified options. The result is in resOut - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) = 0; /// Some compilers have support converting a binary blob into disassembly. Output disassembly is held in the output blob virtual SLANG_NO_THROW SlangResult SLANG_MCALL disassemble(SlangCompileTarget sourceBlobTarget, const void* blob, size_t blobSize, ISlangBlob** out) = 0; @@ -364,25 +229,30 @@ public: Desc m_desc; }; -class CommandLineDownstreamCompileResult : public DownstreamCompileResult +class CommandLineDownstreamArtifactRepresentation : public ComBaseObject, public IArtifactRepresentation { public: - typedef DownstreamCompileResult Super; + SLANG_COM_BASE_IUNKNOWN_ALL - virtual SlangResult getHostCallableSharedLibrary(ComPtr<ISlangSharedLibrary>& outLibrary) SLANG_OVERRIDE; - virtual SlangResult getBinary(ComPtr<ISlangBlob>& outBlob) SLANG_OVERRIDE; + // ICastable + virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; + // IArtifactRepresentation + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createRepresentation(const Guid& typeGuid, ICastable** outCastable) SLANG_OVERRIDE; + virtual SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE; - CommandLineDownstreamCompileResult(const DownstreamDiagnostics& diagnostics, const String& moduleFilePath, TemporaryFileSet* temporaryFileSet) : - Super(diagnostics), + CommandLineDownstreamArtifactRepresentation(const String& moduleFilePath, TemporaryFileSet* temporaryFileSet) : m_moduleFilePath(moduleFilePath), m_temporaryFiles(temporaryFileSet) { } - + RefPtr<TemporaryFileSet> m_temporaryFiles; protected: + void* getInterface(const Guid& guid); + void* getObject(const Guid& guid); + String m_moduleFilePath; DownstreamCompileOptions m_options; ComPtr<ISlangBlob> m_binaryBlob; @@ -396,7 +266,7 @@ public: typedef DownstreamCompilerBase Super; // IDownstreamCompiler - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return true; } // Functions to be implemented for a specific CommandLine @@ -409,7 +279,7 @@ public: virtual SlangResult calcCompileProducts(const CompileOptions& options, DownstreamProductFlags flags, List<String>& outPaths) = 0; virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) = 0; - virtual SlangResult parseOutput(const ExecuteResult& exeResult, DownstreamDiagnostics& output) = 0; + virtual SlangResult parseOutput(const ExecuteResult& exeResult, IArtifactDiagnostics* diagnostics) = 0; CommandLineDownstreamCompiler(const Desc& desc, const ExecutableLocation& exe) : Super(desc) @@ -439,8 +309,6 @@ struct DownstreamCompilerBaseUtil typedef DownstreamProductFlag ProductFlag; typedef DownstreamProductFlags ProductFlags; - - typedef DownstreamDiagnostic Diagnostic; }; } diff --git a/source/compiler-core/slang-downstream-dep1.cpp b/source/compiler-core/slang-downstream-dep1.cpp index e5eb4ac24..25964964f 100644 --- a/source/compiler-core/slang-downstream-dep1.cpp +++ b/source/compiler-core/slang-downstream-dep1.cpp @@ -1,12 +1,136 @@ // slang-downstream-dep1.cpp #include "slang-downstream-dep1.h" +#include "slang-artifact-util.h" +#include "slang-artifact-associated-impl.h" + +#include "../core/slang-castable-list-impl.h" namespace Slang { +/* !!!!!!!!!!!!!!!!!!!!!!!!! DownstreamArtifactRepresentation_Dep1 !!!!!!!!!!!!!!!!!!!!!!!! */ + +class DownstreamResultArtifactRepresentationAdapater_Dep1 : public ComBaseObject, public IArtifactRepresentation +{ +public: + SLANG_COM_BASE_IUNKNOWN_ALL + + // ICastable + virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE; + + // IArtifactRepresentation + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createRepresentation(const Guid& typeGuid, ICastable** outCastable) SLANG_OVERRIDE; + virtual SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE { return true; } + + DownstreamResultArtifactRepresentationAdapater_Dep1(DownstreamCompileResult_Dep1* result): + m_result(result) + { + } + + void* getInterface(const Guid& guid); + void* getObject(const Guid& guid); + + RefPtr<DownstreamCompileResult_Dep1> m_result; +}; + +void* DownstreamResultArtifactRepresentationAdapater_Dep1::castAs(const SlangUUID& guid) +{ + if (auto ptr = getInterface(guid)) + { + return ptr; + } + return getObject(guid); +} + +void* DownstreamResultArtifactRepresentationAdapater_Dep1::getInterface(const Guid& guid) +{ + if (guid == ISlangBlob::getTypeGuid() || + guid == ICastable::getTypeGuid() || + guid == IArtifactRepresentation::getTypeGuid()) + { + IArtifactRepresentation* rep = this; + return rep; + } + return nullptr; +} + +void* DownstreamResultArtifactRepresentationAdapater_Dep1::getObject(const Guid& guid) +{ + SLANG_UNUSED(guid); + return nullptr; +} + +SlangResult DownstreamResultArtifactRepresentationAdapater_Dep1::createRepresentation(const Guid& typeGuid, ICastable** outCastable) +{ + if (typeGuid == ISlangSharedLibrary::getTypeGuid()) + { + ComPtr<ISlangSharedLibrary> lib; + SLANG_RETURN_ON_FAIL(DownstreamUtil_Dep1::getDownstreamSharedLibrary(m_result, lib)); + + *outCastable = lib.detach(); + return SLANG_OK; + } + else if (typeGuid == ISlangBlob::getTypeGuid()) + { + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(m_result->getBinary(blob)); + + *outCastable = CastableUtil::getCastable(blob).detach(); + return SLANG_OK; + } + + return SLANG_E_NOT_AVAILABLE; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompilerAdapter_Dep1 !!!!!!!!!!!!!!!!!!!!!!!! */ + +SlangResult DownstreamCompilerAdapter_Dep1::compile(const CompileOptions& options, IArtifact** outArtifact) +{ + RefPtr<DownstreamCompileResult_Dep1> result; + SLANG_RETURN_ON_FAIL(m_dep->compile(options, result)); + + typedef CharSliceCaster Caster; + + ComPtr<IArtifact> artifact = ArtifactUtil::createArtifactForCompileTarget(options.targetType); + + // Convert the diagnostics + + auto dstDiagnostics = ArtifactDiagnostics::create(); + const DownstreamDiagnostics_Dep1* srcDiagnostics = &result->getDiagnostics(); + + dstDiagnostics->setResult(srcDiagnostics->result); + dstDiagnostics->setRaw(Caster::asCharSlice(srcDiagnostics->rawDiagnostics)); + + for (const auto& srcDiagnostic : srcDiagnostics->diagnostics) + { + IArtifactDiagnostics::Diagnostic dstDiagnostic; + + dstDiagnostic.severity = ArtifactDiagnostic::Severity(srcDiagnostic.severity); + dstDiagnostic.stage = ArtifactDiagnostic::Stage(srcDiagnostic.stage); + + dstDiagnostic.code = Caster::asTerminatedCharSlice(srcDiagnostic.code); + dstDiagnostic.text = Caster::asTerminatedCharSlice(srcDiagnostic.text); + dstDiagnostic.filePath = Caster::asTerminatedCharSlice(srcDiagnostic.filePath); + + dstDiagnostic.location.line = srcDiagnostic.fileLine; + } + + artifact->addAssociated(dstDiagnostics); + + // We need to add a representation that can produce shared libraries/blobs on demand + + auto rep = new DownstreamResultArtifactRepresentationAdapater_Dep1(result); + artifact->addRepresentation(rep); + + *outArtifact = artifact.detach(); + return SLANG_OK; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!! SharedLibraryDep1Adapter !!!!!!!!!!!!!!!!!!!!!!!! */ + // A temporary class that adapts `ISlangSharedLibrary_Dep1` to ISlangSharedLibrary -class SharedLibraryDep1Adapter : public ComBaseObject, public ISlangSharedLibrary +class SharedLibraryAdapter_Dep1 : public ComBaseObject, public ISlangSharedLibrary { public: SLANG_COM_BASE_IUNKNOWN_ALL @@ -17,7 +141,7 @@ public: // ISlangSharedLibrary virtual SLANG_NO_THROW void* SLANG_MCALL findSymbolAddressByName(char const* name) SLANG_OVERRIDE { return m_contained->findSymbolAddressByName(name); } - SharedLibraryDep1Adapter(ISlangSharedLibrary_Dep1* dep1) : + SharedLibraryAdapter_Dep1(ISlangSharedLibrary_Dep1* dep1) : m_contained(dep1) { } @@ -42,7 +166,7 @@ protected: ComPtr<ISlangSharedLibrary_Dep1> m_contained; }; -void* SharedLibraryDep1Adapter::castAs(const SlangUUID& guid) +void* SharedLibraryAdapter_Dep1::castAs(const SlangUUID& guid) { if (auto intf = getInterface(guid)) { @@ -52,7 +176,7 @@ void* SharedLibraryDep1Adapter::castAs(const SlangUUID& guid) } /* Hack to take into account downstream compilers shared library interface might need an adapter */ -/* static */SlangResult DownstreamUtil_Dep1::getDownstreamSharedLibrary(DownstreamCompileResult* downstreamResult, ComPtr<ISlangSharedLibrary>& outSharedLibrary) +/* static */SlangResult DownstreamUtil_Dep1::getDownstreamSharedLibrary(DownstreamCompileResult_Dep1* downstreamResult, ComPtr<ISlangSharedLibrary>& outSharedLibrary) { ComPtr<ISlangSharedLibrary> lib; SLANG_RETURN_ON_FAIL(downstreamResult->getHostCallableSharedLibrary(lib)); @@ -66,7 +190,7 @@ void* SharedLibraryDep1Adapter::castAs(const SlangUUID& guid) if (SLANG_SUCCEEDED(lib->queryInterface(ISlangSharedLibrary_Dep1::getTypeGuid(), (void**)libDep1.writeRef()))) { // Okay, we need to adapt for now - outSharedLibrary = new SharedLibraryDep1Adapter(libDep1); + outSharedLibrary = new SharedLibraryAdapter_Dep1(libDep1); return SLANG_OK; } return SLANG_E_NOT_FOUND; diff --git a/source/compiler-core/slang-downstream-dep1.h b/source/compiler-core/slang-downstream-dep1.h index fd0efd1e9..19d8a6d68 100644 --- a/source/compiler-core/slang-downstream-dep1.h +++ b/source/compiler-core/slang-downstream-dep1.h @@ -8,6 +8,59 @@ namespace Slang { // (DEPRECIATED) +struct DownstreamDiagnostic_Dep1 +{ + enum class Severity + { + Unknown, + Info, + Warning, + Error, + CountOf, + }; + enum class Stage + { + Compile, + Link, + }; + + Severity severity = Severity::Unknown; ///< The severity of error + Stage stage = Stage::Compile; ///< The stage the error came from + String text; ///< The text of the error + String code; ///< The compiler specific error code + String filePath; ///< The path the error originated from + Int fileLine = 0; ///< The line number the error came from +}; + +struct DownstreamDiagnostics_Dep1 +{ + typedef DownstreamDiagnostic_Dep1 Diagnostic; + + String rawDiagnostics; + + SlangResult result = SLANG_OK; + List<Diagnostic> diagnostics; +}; + +class DownstreamCompileResult_Dep1 : public RefObject +{ +public: + SLANG_CLASS_GUID(0xdfc5d318, 0x8675, 0x40ef, { 0xbd, 0x7b, 0x4, 0xa4, 0xff, 0x66, 0x11, 0x30 }) + + virtual SlangResult getHostCallableSharedLibrary(ComPtr<ISlangSharedLibrary>& outLibrary) { SLANG_UNUSED(outLibrary); return SLANG_FAIL; } + virtual SlangResult getBinary(ComPtr<ISlangBlob>& outBlob) { SLANG_UNUSED(outBlob); return SLANG_FAIL; } + + const DownstreamDiagnostics_Dep1& getDiagnostics() const { return m_diagnostics; } + + /// Ctor + DownstreamCompileResult_Dep1(const DownstreamDiagnostics_Dep1& diagnostics) : + m_diagnostics(diagnostics) + {} + +protected: + DownstreamDiagnostics_Dep1 m_diagnostics; +}; + class DownstreamCompiler_Dep1: public RefObject { public: @@ -16,7 +69,7 @@ public: /// Get the desc of this compiler const DownstreamCompilerDesc& getDesc() const { return m_desc; } /// Compile using the specified options. The result is in resOut - virtual SlangResult compile(const DownstreamCompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) = 0; + virtual SlangResult compile(const DownstreamCompileOptions& options, RefPtr<DownstreamCompileResult_Dep1>& outResult) = 0; /// Some compilers have support converting a binary blob into disassembly. Output disassembly is held in the output blob virtual SlangResult disassemble(SlangCompileTarget sourceBlobTarget, const void* blob, size_t blobSize, ISlangBlob** out); @@ -33,7 +86,7 @@ class DownstreamCompilerAdapter_Dep1 : public DownstreamCompilerBase public: // IDownstreamCompiler virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() SLANG_OVERRIDE { return m_dep->getDesc(); } - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) SLANG_OVERRIDE { return m_dep->compile(options, outResult); } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL disassemble(SlangCompileTarget sourceBlobTarget, const void* blob, size_t blobSize, ISlangBlob** out) SLANG_OVERRIDE { return m_dep->disassemble(sourceBlobTarget, blob, blobSize, out); } virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return m_dep->isFileBased(); } @@ -48,7 +101,7 @@ protected: struct DownstreamUtil_Dep1 { - static SlangResult getDownstreamSharedLibrary(DownstreamCompileResult* downstreamResult, ComPtr<ISlangSharedLibrary>& outSharedLibrary); + static SlangResult getDownstreamSharedLibrary(DownstreamCompileResult_Dep1* downstreamResult, ComPtr<ISlangSharedLibrary>& outSharedLibrary); }; } diff --git a/source/compiler-core/slang-dxc-compiler.cpp b/source/compiler-core/slang-dxc-compiler.cpp index 5126e53cc..7a3281463 100644 --- a/source/compiler-core/slang-dxc-compiler.cpp +++ b/source/compiler-core/slang-dxc-compiler.cpp @@ -19,7 +19,9 @@ #include "../core/slang-shared-library.h" -#include "../compiler-core/slang-artifact-util.h" +#include "slang-artifact-associated-impl.h" +#include "slang-artifact-util.h" +#include "slang-artifact-diagnostic-util.h" // Enable calling through to `dxc` to // generate code on Windows. @@ -161,7 +163,7 @@ public: typedef DownstreamCompilerBase Super; // IDownstreamCompiler - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL disassemble(SlangCompileTarget sourceBlobTarget, const void* blob, size_t blobSize, ISlangBlob** out) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; } @@ -192,7 +194,7 @@ SlangResult DXCDownstreamCompiler::init(ISlangSharedLibrary* library) return SLANG_OK; } -static SlangResult _parseDiagnosticLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic) +static SlangResult _parseDiagnosticLine(CharSliceAllocator& allocator, const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, IArtifactDiagnostics::Diagnostic& outDiagnostic) { /* tests/diagnostics/syntax-error-intrinsic.slang:14:2: error: expected expression */ if (lineSlices.getCount() < 5) @@ -200,27 +202,27 @@ static SlangResult _parseDiagnosticLine(const UnownedStringSlice& line, List<Uno return SLANG_FAIL; } - outDiagnostic.filePath = lineSlices[0]; + outDiagnostic.filePath = allocator.allocate(lineSlices[0]); - SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[1], outDiagnostic.fileLine)); + SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[1], outDiagnostic.location.line)); //Int lineCol; //SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[2], lineCol)); UnownedStringSlice severitySlice = lineSlices[3].trim(); - outDiagnostic.severity = DownstreamDiagnostic::Severity::Error; + outDiagnostic.severity = ArtifactDiagnostic::Severity::Error; if (severitySlice == UnownedStringSlice::fromLiteral("warning")) { - outDiagnostic.severity = DownstreamDiagnostic::Severity::Warning; + outDiagnostic.severity = ArtifactDiagnostic::Severity::Warning; } // The rest of the line - outDiagnostic.text = UnownedStringSlice(lineSlices[4].begin(), line.end()); + outDiagnostic.text = allocator.allocate(lineSlices[4].begin(), line.end()); return SLANG_OK; } -static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, DownstreamDiagnostics& ioDiagnostics, ComPtr<IDxcBlob>& outBlob) +static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, IArtifactDiagnostics* diagnostics, ComPtr<IDxcBlob>& outBlob) { // Retrieve result. HRESULT resultCode = S_OK; @@ -231,9 +233,9 @@ static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, Downst // *unless* the compile failed (no way to get // warnings out!?). - if (SLANG_SUCCEEDED(ioDiagnostics.result)) + if (SLANG_SUCCEEDED(diagnostics->getResult())) { - ioDiagnostics.result = resultCode; + diagnostics->setResult(resultCode); } // Try getting the error/diagnostics blob @@ -245,13 +247,11 @@ static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, Downst const UnownedStringSlice diagnosticsSlice = _getSlice(dxcErrorBlob); if (diagnosticsSlice.getLength()) { - if (ioDiagnostics.rawDiagnostics.getLength() > 0) - { - ioDiagnostics.rawDiagnostics.append("\n"); - } - ioDiagnostics.rawDiagnostics.append(diagnosticsSlice); + diagnostics->appendRaw(asCharSlice(diagnosticsSlice)); - SlangResult diagnosticParseRes = DownstreamDiagnostic::parseColonDelimitedDiagnostics(diagnosticsSlice, 0, _parseDiagnosticLine, ioDiagnostics.diagnostics); + CharSliceAllocator allocator; + List<IArtifactDiagnostics::Diagnostic> parsedDiagnostics; + SlangResult diagnosticParseRes = ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics(allocator, diagnosticsSlice, 0, _parseDiagnosticLine, diagnostics); SLANG_UNUSED(diagnosticParseRes); SLANG_ASSERT(SLANG_SUCCEEDED(diagnosticParseRes)); @@ -262,7 +262,7 @@ static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, Downst if (SLANG_FAILED(resultCode)) { // In case the parsing failed, we still have an error -> so require there is one in the diagnostics - ioDiagnostics.requireErrorDiagnostic(); + diagnostics->requireErrorDiagnostic(); } else { @@ -274,7 +274,7 @@ static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, Downst return SLANG_OK; } -SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) +SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, IArtifact** outArtifact) { // This compiler doesn't read files, they should be read externally and stored in sourceContents/sourceContentsPath if (options.sourceFiles.getCount() > 0) @@ -446,8 +446,8 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, RefPtr &includeHandler, // `#include` handler dxcResult.writeRef())); - DownstreamDiagnostics diagnostics; - + auto diagnostics = ArtifactDiagnostics::create(); + ComPtr<IDxcBlob> dxcResultBlob; SLANG_RETURN_ON_FAIL(_handleOperationResult(dxcResult, diagnostics, dxcResultBlob)); @@ -517,7 +517,14 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, RefPtr dxcResultBlob = linkedBlob; } - outResult = new BlobDownstreamCompileResult(diagnostics, (ISlangBlob*)dxcResultBlob.get()); + auto artifact = ArtifactUtil::createArtifactForCompileTarget(options.targetType); + artifact->addAssociated(diagnostics); + if (dxcResultBlob) + { + artifact->addRepresentationUnknown((ISlangBlob*)dxcResultBlob.get()); + } + + *outArtifact = artifact.detach(); return SLANG_OK; } diff --git a/source/compiler-core/slang-fxc-compiler.cpp b/source/compiler-core/slang-fxc-compiler.cpp index d9d506221..21cd14759 100644 --- a/source/compiler-core/slang-fxc-compiler.cpp +++ b/source/compiler-core/slang-fxc-compiler.cpp @@ -17,6 +17,10 @@ #include "slang-include-system.h" #include "slang-source-loc.h" +#include "slang-artifact-associated-impl.h" + +#include "slang-artifact-diagnostic-util.h" + #include "../core/slang-shared-library.h" // Enable calling through to `fxc` or `dxc` to @@ -113,7 +117,7 @@ public: typedef DownstreamCompilerBase Super; // IDownstreamCompiler - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL disassemble(SlangCompileTarget sourceBlobTarget, const void* blob, size_t blobSize, ISlangBlob** out) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; } @@ -148,7 +152,7 @@ SlangResult FXCDownstreamCompiler::init(ISlangSharedLibrary* library) return SLANG_OK; } -static SlangResult _parseDiagnosticLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic) +static SlangResult _parseDiagnosticLine(CharSliceAllocator& allocator, const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, ArtifactDiagnostic& outDiagnostic) { /* tests/diagnostics/syntax-error-intrinsic.slang(14,2): error X3000: syntax error: unexpected token '@' */ if (lineSlices.getCount() < 3) @@ -156,26 +160,26 @@ static SlangResult _parseDiagnosticLine(const UnownedStringSlice& line, List<Uno return SLANG_FAIL; } - SLANG_RETURN_ON_FAIL(DownstreamDiagnostic::splitPathLocation(lineSlices[0], outDiagnostic)); + SLANG_RETURN_ON_FAIL(ArtifactDiagnosticUtil::splitPathLocation(allocator, lineSlices[0], outDiagnostic)); { const UnownedStringSlice severityAndCodeSlice = lineSlices[1].trim(); const UnownedStringSlice severitySlice = StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 0); - outDiagnostic.code = StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 1); + outDiagnostic.code = allocator.allocate(StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 1)); - outDiagnostic.severity = DownstreamDiagnostic::Severity::Error; + outDiagnostic.severity = ArtifactDiagnostic::Severity::Error; if (severitySlice == "warning") { - outDiagnostic.severity = DownstreamDiagnostic::Severity::Warning; + outDiagnostic.severity = ArtifactDiagnostic::Severity::Warning; } } - outDiagnostic.text = UnownedStringSlice(lineSlices[2].begin(), line.end()); + outDiagnostic.text = allocator.allocate(lineSlices[2].begin(), line.end()); return SLANG_OK; } -SlangResult FXCDownstreamCompiler::compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) +SlangResult FXCDownstreamCompiler::compile(const CompileOptions& options, IArtifact** outArtifact) { // This compiler doesn't read files, they should be read externally and stored in sourceContents/sourceContentsPath if (options.sourceFiles.getCount() > 0) @@ -284,17 +288,19 @@ SlangResult FXCDownstreamCompiler::compile(const CompileOptions& options, RefPtr codeBlob.writeRef(), diagnosticsBlob.writeRef()); - DownstreamDiagnostics diagnostics; + auto diagnostics = ArtifactDiagnostics::create(); // HRESULT is compatible with SlangResult - diagnostics.result = hr; + diagnostics->setResult(hr); + + CharSliceAllocator allocator; if (diagnosticsBlob) { UnownedStringSlice diagnosticText = _getSlice(diagnosticsBlob); - diagnostics.rawDiagnostics = diagnosticText; + diagnostics->setRaw(asCharSlice(diagnosticText)); - SlangResult diagnosticParseRes = DownstreamDiagnostic::parseColonDelimitedDiagnostics(diagnosticText, 0, _parseDiagnosticLine, diagnostics.diagnostics); + SlangResult diagnosticParseRes = ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics(allocator, diagnosticText, 0, _parseDiagnosticLine, diagnostics); SLANG_UNUSED(diagnosticParseRes); SLANG_ASSERT(SLANG_SUCCEEDED(diagnosticParseRes)); } @@ -302,13 +308,19 @@ SlangResult FXCDownstreamCompiler::compile(const CompileOptions& options, RefPtr // If FXC failed, make sure we have an error in the diagnostics if (FAILED(hr)) { - diagnostics.requireErrorDiagnostic(); + diagnostics->requireErrorDiagnostic(); } - // ID3DBlob is compatible with ISlangBlob, so just cast away... - ISlangBlob* slangCodeBlob = (ISlangBlob*)codeBlob.get(); + auto artifact = ArtifactUtil::createArtifactForCompileTarget(options.targetType); + artifact->addAssociated(diagnostics); + + if (codeBlob) + { + // ID3DBlob is compatible with ISlangBlob, so just cast away... + artifact->addRepresentationUnknown((ISlangBlob*)codeBlob.get()); + } - outResult = new BlobDownstreamCompileResult(diagnostics, slangCodeBlob); + *outArtifact = artifact.detach(); return SLANG_OK; } diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index 61cf5640a..d33e72824 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -11,6 +11,7 @@ #include "../core/slang-string-slice-pool.h" #include "slang-artifact-desc-util.h" +#include "slang-artifact-diagnostic-util.h" #include "slang-artifact-util.h" namespace Slang @@ -130,9 +131,9 @@ SlangResult GCCDownstreamCompilerUtil::calcVersion(const ExecutableLocation& exe return SLANG_FAIL; } -static SlangResult _parseSeverity(const UnownedStringSlice& in, DownstreamDiagnostic::Severity& outSeverity) +static SlangResult _parseSeverity(const UnownedStringSlice& in, ArtifactDiagnostic::Severity& outSeverity) { - typedef DownstreamDiagnostic::Severity Severity; + typedef ArtifactDiagnostic::Severity Severity; if (in == "error" || in == "fatal error") { @@ -165,9 +166,9 @@ enum class LineParseResult } // anonymous -static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParseResult& outLineParseResult, DownstreamDiagnostic& outDiagnostic) +static SlangResult _parseGCCFamilyLine(CharSliceAllocator& allocator, const UnownedStringSlice& line, LineParseResult& outLineParseResult, ArtifactDiagnostic& outDiagnostic) { - typedef DownstreamDiagnostic Diagnostic; + typedef ArtifactDiagnostic Diagnostic; typedef Diagnostic::Severity Severity; // Set to default case @@ -238,7 +239,7 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse // We'll ignore for now outDiagnostic.stage = Diagnostic::Stage::Link; outDiagnostic.severity = Severity::Info; - outDiagnostic.text = split[1].trim(); + outDiagnostic.text = allocator.allocate(split[1].trim()); outLineParseResult = LineParseResult::Start; return SLANG_OK; } @@ -247,7 +248,7 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse { // Command line errors can be just contain 'error:' etc. Can be seen on apple/clang outDiagnostic.stage = Diagnostic::Stage::Compile; - outDiagnostic.text = split[1].trim(); + outDiagnostic.text = allocator.allocate(split[1].trim()); outLineParseResult = LineParseResult::Single; return SLANG_OK; } @@ -275,25 +276,25 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse outDiagnostic.stage = Diagnostic::Stage::Link; } - outDiagnostic.text = text; + outDiagnostic.text = allocator.allocate(text); outLineParseResult = LineParseResult::Start; return SLANG_OK; } else if (split1.startsWith("(.text")) { // This is a little weak... but looks like it's a link error - outDiagnostic.filePath = split[0]; + outDiagnostic.filePath = allocator.allocate(split[0]); outDiagnostic.severity = Severity::Error; outDiagnostic.stage = Diagnostic::Stage::Link; - outDiagnostic.text = text; + outDiagnostic.text = allocator.allocate(text); outLineParseResult = LineParseResult::Single; return SLANG_OK; } else if (text.startsWith("ld returned")) { - outDiagnostic.stage = DownstreamDiagnostic::Stage::Link; + outDiagnostic.stage = ArtifactDiagnostic::Stage::Link; SLANG_RETURN_ON_FAIL(_parseSeverity(split[1].trim(), outDiagnostic.severity)); - outDiagnostic.text = line; + outDiagnostic.text = allocator.allocate(line); outLineParseResult = LineParseResult::Single; return SLANG_OK; } @@ -317,11 +318,12 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse } else { - outDiagnostic.filePath = split[1]; - outDiagnostic.fileLine = 0; + outDiagnostic.filePath = allocator.allocate(split[1]); + outDiagnostic.location.line = 0; + outDiagnostic.location.column = 0; outDiagnostic.severity = Diagnostic::Severity::Error; outDiagnostic.stage = Diagnostic::Stage::Link; - outDiagnostic.text = split[3]; + outDiagnostic.text = allocator.allocate(split[3]); outLineParseResult = LineParseResult::Start; return SLANG_OK; @@ -332,11 +334,11 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse // Probably a regular error line SLANG_RETURN_ON_FAIL(_parseSeverity(split[3].trim(), outDiagnostic.severity)); - outDiagnostic.filePath = split[0]; - SLANG_RETURN_ON_FAIL(StringUtil::parseInt(split[1], outDiagnostic.fileLine)); + outDiagnostic.filePath = allocator.allocate(split[0]); + SLANG_RETURN_ON_FAIL(StringUtil::parseInt(split[1], outDiagnostic.location.line)); // Everything from 4 to the end is the error - outDiagnostic.text = UnownedStringSlice(split[4].begin(), split.getLast().end()); + outDiagnostic.text = allocator.allocate(split[4].begin(), split.getLast().end()); outLineParseResult = LineParseResult::Start; return SLANG_OK; @@ -347,35 +349,40 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse return SLANG_OK; } -/* static */SlangResult GCCDownstreamCompilerUtil::parseOutput(const ExecuteResult& exeRes, DownstreamDiagnostics& outOutput) +/* static */SlangResult GCCDownstreamCompilerUtil::parseOutput(const ExecuteResult& exeRes, IArtifactDiagnostics* diagnostics) { LineParseResult prevLineResult = LineParseResult::Ignore; - outOutput.reset(); - outOutput.rawDiagnostics = exeRes.standardError; + CharSliceAllocator allocator; + + diagnostics->reset(); + diagnostics->setRaw(CharSliceCaster::asCharSlice(exeRes.standardError)); + + // We hold in workDiagnostics so as it is more convenient to append to the last with a continuation + // also means we don't hold the allocations of building up continuations, just the results when finally allocated at the end + List<ArtifactDiagnostic> workDiagnostics; for (auto line : LineParser(exeRes.standardError.getUnownedSlice())) { - Diagnostic diagnostic; - diagnostic.reset(); - + ArtifactDiagnostic diagnostic; + LineParseResult lineRes; - SLANG_RETURN_ON_FAIL(_parseGCCFamilyLine(line, lineRes, diagnostic)); + SLANG_RETURN_ON_FAIL(_parseGCCFamilyLine(allocator, line, lineRes, diagnostic)); switch (lineRes) { case LineParseResult::Start: { // It's start of a new message - outOutput.diagnostics.add(diagnostic); + workDiagnostics.add(diagnostic); prevLineResult = LineParseResult::Start; break; } case LineParseResult::Single: { // It's a single message, without anything following - outOutput.diagnostics.add(diagnostic); + workDiagnostics.add(diagnostic); prevLineResult = LineParseResult::Ignore; break; } @@ -383,12 +390,21 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse { if (prevLineResult == LineParseResult::Start || prevLineResult == LineParseResult::Continuation) { - if (outOutput.diagnostics.getCount() > 0) + if (workDiagnostics.getCount() > 0) { + auto& last = workDiagnostics.getLast(); + + // TODO(JS): Note that this is somewhat wasteful as every time we append we just allocate more memory + // to hold the result. + // If we had an allocator dedicated to 'text' we could perhaps just append to the end of the last allocation + // // We are now in a continuation, add to the last - auto& text = outOutput.diagnostics.getLast().text; - text.append("\n"); - text.append(line); + StringBuilder buf; + buf.append(asStringSlice(last.text)); + buf.append("\n"); + buf.append(line); + + last.text = allocator.allocate(buf); } prevLineResult = LineParseResult::Continuation; } @@ -403,9 +419,14 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse } } - if (outOutput.has(Diagnostic::Severity::Error) || exeRes.resultCode != 0) + for (const auto& diagnostic : workDiagnostics) + { + diagnostics->add(diagnostic); + } + + if (diagnostics->hasOfAtLeastSeverity(ArtifactDiagnostic::Severity::Error) || exeRes.resultCode != 0) { - outOutput.result = SLANG_FAIL; + diagnostics->setResult(SLANG_FAIL); } return SLANG_OK; diff --git a/source/compiler-core/slang-gcc-compiler-util.h b/source/compiler-core/slang-gcc-compiler-util.h index ec8b21e03..7f15f6701 100644 --- a/source/compiler-core/slang-gcc-compiler-util.h +++ b/source/compiler-core/slang-gcc-compiler-util.h @@ -19,7 +19,7 @@ struct GCCDownstreamCompilerUtil : public DownstreamCompilerBaseUtil static SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine); /// Parse ExecuteResult into diagnostics - static SlangResult parseOutput(const ExecuteResult& exeRes, DownstreamDiagnostics& out); + static SlangResult parseOutput(const ExecuteResult& exeRes, IArtifactDiagnostics* diagnostics); /// Calculate the output module filename static SlangResult calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath); @@ -46,7 +46,7 @@ public: // CommandLineCPPCompiler impl - just forwards to the Util virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) SLANG_OVERRIDE { return Util::calcArgs(options, cmdLine); } - virtual SlangResult parseOutput(const ExecuteResult& exeResult, DownstreamDiagnostics& output) SLANG_OVERRIDE { return Util::parseOutput(exeResult, output); } + virtual SlangResult parseOutput(const ExecuteResult& exeResult, IArtifactDiagnostics* diagnostics) SLANG_OVERRIDE { return Util::parseOutput(exeResult, diagnostics); } virtual SlangResult calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath) SLANG_OVERRIDE { return Util::calcModuleFilePath(options, outPath); } virtual SlangResult calcCompileProducts(const CompileOptions& options, DownstreamProductFlags flags, List<String>& outPaths) SLANG_OVERRIDE { return Util::calcCompileProducts(options, flags, outPaths); } diff --git a/source/compiler-core/slang-glslang-compiler.cpp b/source/compiler-core/slang-glslang-compiler.cpp index b4e3d915d..5ae9419fd 100644 --- a/source/compiler-core/slang-glslang-compiler.cpp +++ b/source/compiler-core/slang-glslang-compiler.cpp @@ -14,6 +14,8 @@ #include "../core/slang-semantic-version.h" #include "../core/slang-char-util.h" +#include "slang-artifact-associated-impl.h" + #include "slang-include-system.h" #include "slang-source-loc.h" @@ -40,7 +42,7 @@ public: typedef DownstreamCompilerBase Super; // IDownstreamCompiler - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outResult) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL disassemble(SlangCompileTarget sourceBlobTarget, const void* blob, size_t blobSize, ISlangBlob** out) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; } @@ -94,7 +96,7 @@ SlangResult GlslangDownstreamCompiler::_invoke(glslang_CompileRequest_1_1& reque return err ? SLANG_FAIL : SLANG_OK; } -static SlangResult _parseDiagnosticLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic) +static SlangResult _parseDiagnosticLine(CharSliceAllocator& allocator, const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, ArtifactDiagnostic& outDiagnostic) { /* ERROR: tests/diagnostics/syntax-error-intrinsic.slang:13: '@' : unexpected token */ @@ -105,23 +107,23 @@ static SlangResult _parseDiagnosticLine(const UnownedStringSlice& line, List<Uno { const UnownedStringSlice severitySlice = lineSlices[0].trim(); - outDiagnostic.severity = DownstreamDiagnostic::Severity::Error; + outDiagnostic.severity = ArtifactDiagnostic::Severity::Error; if (severitySlice.caseInsensitiveEquals(UnownedStringSlice::fromLiteral("warning"))) { - outDiagnostic.severity = DownstreamDiagnostic::Severity::Warning; + outDiagnostic.severity = ArtifactDiagnostic::Severity::Warning; } } - outDiagnostic.filePath = lineSlices[1]; + outDiagnostic.filePath = allocator.allocate(lineSlices[1]); - SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[2], outDiagnostic.fileLine)); - outDiagnostic.text = UnownedStringSlice(lineSlices[3].begin(), line.end()); + SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[2], outDiagnostic.location.line)); + outDiagnostic.text = allocator.allocate(lineSlices[3].begin(), line.end()); return SLANG_OK; } -SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) +SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& options, IArtifact** outArtifact) { // This compiler doesn't read files, they should be read externally and stored in sourceContents/sourceContentsPath if (options.sourceFiles.getCount() > 0) @@ -187,27 +189,31 @@ SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& options, Re const SlangResult invokeResult = _invoke(request); - DownstreamDiagnostics diagnostics; + auto artifact = ArtifactUtil::createArtifactForCompileTarget(options.targetType); + + auto diagnostics = ArtifactDiagnostics::create(); // Set the diagnostics result - diagnostics.result = invokeResult; + diagnostics->setResult(invokeResult); + artifact->addAssociated(diagnostics); if (SLANG_FAILED(invokeResult)) { - diagnostics.rawDiagnostics = diagnosticOutput; + diagnostics->setRaw(CharSliceCaster::asCharSlice(diagnosticOutput)); - SlangResult diagnosticParseRes = DownstreamDiagnostic::parseColonDelimitedDiagnostics(diagnosticOutput.getUnownedSlice(), 1, _parseDiagnosticLine, diagnostics.diagnostics); - SLANG_UNUSED(diagnosticParseRes); + CharSliceAllocator allocator; - diagnostics.requireErrorDiagnostic(); + SlangResult diagnosticParseRes = ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics(allocator, diagnosticOutput.getUnownedSlice(), 1, _parseDiagnosticLine, diagnostics); + SLANG_UNUSED(diagnosticParseRes); - outResult = new BlobDownstreamCompileResult(diagnostics, nullptr); - return SLANG_OK; + diagnostics->requireErrorDiagnostic(); + } + else + { + artifact->addRepresentationUnknown(ListBlob::moveCreate(spirv)); } - ComPtr<ISlangBlob> spirvBlob = ListBlob::moveCreate(spirv); - outResult = new BlobDownstreamCompileResult(diagnostics, spirvBlob); - + *outArtifact = artifact.detach(); return SLANG_OK; } diff --git a/source/compiler-core/slang-nvrtc-compiler.cpp b/source/compiler-core/slang-nvrtc-compiler.cpp index 0cc208854..683aeaedc 100644 --- a/source/compiler-core/slang-nvrtc-compiler.cpp +++ b/source/compiler-core/slang-nvrtc-compiler.cpp @@ -15,6 +15,10 @@ #include "../core/slang-shared-library.h" +#include "slang-artifact-diagnostic-util.h" +#include "slang-artifact-util.h" +#include "slang-artifact-associated-impl.h" + namespace nvrtc { @@ -98,7 +102,7 @@ public: typedef DownstreamCompilerBase Super; // IDownstreamCompiler - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; } /// Must be called before use @@ -166,13 +170,13 @@ SlangResult NVRTCDownstreamCompiler::init(ISlangSharedLibrary* library) return SLANG_OK; } -static SlangResult _parseLocation(const UnownedStringSlice& in, DownstreamDiagnostic& outDiagnostic) +static SlangResult _parseLocation(CharSliceAllocator& allocator, const UnownedStringSlice& in, ArtifactDiagnostic& outDiagnostic) { const Index startIndex = in.indexOf('('); if (startIndex >= 0) { - outDiagnostic.filePath = UnownedStringSlice(in.begin(), in.begin() + startIndex); + outDiagnostic.filePath = allocator.allocate(in.begin(), in.begin() + startIndex); UnownedStringSlice remaining(in.begin() + startIndex + 1, in.end()); const Int endIndex = remaining.indexOf(')'); @@ -180,12 +184,12 @@ static SlangResult _parseLocation(const UnownedStringSlice& in, DownstreamDiagno Int line; SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineText, line)); - outDiagnostic.fileLine = line; + outDiagnostic.location.line = line; } else { - outDiagnostic.fileLine = 0; - outDiagnostic.filePath = in; + outDiagnostic.location.line = 0; + outDiagnostic.filePath = allocator.allocate(in); } return SLANG_OK; } @@ -200,10 +204,10 @@ static bool _hasDriveLetter(const UnownedStringSlice& line) return line.getLength() > 2 && line[1] == ':' && _isDriveLetter(line[0]); } -static SlangResult _parseNVRTCLine(const UnownedStringSlice& line, DownstreamDiagnostic& outDiagnostic) +static SlangResult _parseNVRTCLine(CharSliceAllocator& allocator, const UnownedStringSlice& line, ArtifactDiagnostic& outDiagnostic) { - typedef DownstreamDiagnostic Diagnostic; - typedef Diagnostic::Severity Severity; + typedef ArtifactDiagnostic Diagnostic; + typedef ArtifactDiagnostic::Severity Severity; outDiagnostic.stage = Diagnostic::Stage::Compile; @@ -234,9 +238,9 @@ static SlangResult _parseNVRTCLine(const UnownedStringSlice& line, DownstreamDia { outDiagnostic.severity = Severity::Warning; } - outDiagnostic.text = split[2].trim(); + outDiagnostic.text = allocator.allocate(split[2].trim()); - SLANG_RETURN_ON_FAIL(_parseLocation(split[0], outDiagnostic)); + SLANG_RETURN_ON_FAIL(_parseLocation(allocator, split[0], outDiagnostic)); return SLANG_OK; } @@ -637,7 +641,7 @@ SlangResult NVRTCDownstreamCompiler::_maybeAddHalfSupport(const DownstreamCompil return SLANG_OK; } -SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) +SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& options, IArtifact** outArtifact) { // This compiler doesn't read files, they should be read externally and stored in sourceContents/sourceContentsPath if (options.sourceFiles.getCount() > 0) @@ -833,10 +837,14 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& opt res = m_nvrtcCompileProgram(program, int(dstOptions.getCount()), dstOptions.getBuffer()); + auto artifact = ArtifactUtil::createArtifactForCompileTarget(options.targetType); + auto diagnostics = ArtifactDiagnostics::create(); + + artifact->addAssociated(diagnostics); + ComPtr<ISlangBlob> blob; - DownstreamDiagnostics diagnostics; - diagnostics.result = _asResult(res); + diagnostics->setResult(_asResult(res)); { String rawDiagnostics; @@ -850,18 +858,20 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& opt SLANG_NVRTC_RETURN_ON_FAIL(m_nvrtcGetProgramLog(program, dst)); rawDiagnostics.appendInPlace(dst, Index(logSize)); - diagnostics.rawDiagnostics = rawDiagnostics; + diagnostics->setRaw(CharSliceCaster::asCharSlice(rawDiagnostics)); } + CharSliceAllocator allocator; + // Parse the diagnostics here - for (auto line : LineParser(diagnostics.rawDiagnostics.getUnownedSlice())) + for (auto line : LineParser(rawDiagnostics.getUnownedSlice())) { - DownstreamDiagnostic diagnostic; - SlangResult lineRes = _parseNVRTCLine(line, diagnostic); + ArtifactDiagnostic diagnostic; + SlangResult lineRes = _parseNVRTCLine(allocator, line, diagnostic); if (SLANG_SUCCEEDED(lineRes)) { - diagnostics.diagnostics.add(diagnostic); + diagnostics->add(diagnostic); } else if (lineRes != SLANG_E_NOT_FOUND) { @@ -870,9 +880,9 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& opt } // if it has a compilation error.. set on output - if (diagnostics.has(DownstreamDiagnostic::Severity::Error)) + if (diagnostics->hasOfAtLeastSeverity(ArtifactDiagnostic::Severity::Error)) { - diagnostics.result = SLANG_FAIL; + diagnostics->setResult(SLANG_FAIL); } } @@ -887,11 +897,10 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& opt SLANG_NVRTC_RETURN_ON_FAIL(m_nvrtcGetPTX(program, (char*)ptx.getBuffer())); - blob = ListBlob::moveCreate(ptx); + artifact->addRepresentationUnknown(ListBlob::moveCreate(ptx)); } - outResult = new BlobDownstreamCompileResult(diagnostics, blob); - + *outArtifact = artifact.detach(); return SLANG_OK; } diff --git a/source/compiler-core/slang-visual-studio-compiler-util.cpp b/source/compiler-core/slang-visual-studio-compiler-util.cpp index 21db9570a..4e703f58f 100644 --- a/source/compiler-core/slang-visual-studio-compiler-util.cpp +++ b/source/compiler-core/slang-visual-studio-compiler-util.cpp @@ -14,6 +14,7 @@ #include "../core/slang-io.h" #include "slang-artifact-desc-util.h" +#include "slang-artifact-diagnostic-util.h" #include "slang-artifact-util.h" namespace Slang @@ -288,21 +289,21 @@ namespace Slang return SLANG_OK; } -static SlangResult _parseSeverity(const UnownedStringSlice& in, DownstreamDiagnostics::Diagnostic::Severity& outSeverity) +static SlangResult _parseSeverity(const UnownedStringSlice& in, ArtifactDiagnostic::Severity& outSeverity) { - typedef DownstreamDiagnostics::Diagnostic::Severity Type; + typedef ArtifactDiagnostic::Severity Severity; if (in == "error" || in == "fatal error") { - outSeverity = Type::Error; + outSeverity = Severity::Error; } else if (in == "warning") { - outSeverity = Type::Warning; + outSeverity = Severity::Warning; } else if (in == "info") { - outSeverity = Type::Info; + outSeverity = Severity::Info; } else { @@ -311,22 +312,22 @@ static SlangResult _parseSeverity(const UnownedStringSlice& in, DownstreamDiagno return SLANG_OK; } -static SlangResult _parseVisualStudioLine(const UnownedStringSlice& line, DownstreamDiagnostics::Diagnostic& outDiagnostic) +static SlangResult _parseVisualStudioLine(CharSliceAllocator& allocator, const UnownedStringSlice& line, ArtifactDiagnostic& outDiagnostic) { - typedef DownstreamDiagnostics::Diagnostic Diagnostic; + typedef IArtifactDiagnostics::Diagnostic Diagnostic; UnownedStringSlice linkPrefix = UnownedStringSlice::fromLiteral("LINK :"); if (line.startsWith(linkPrefix)) { - outDiagnostic.stage = Diagnostic::Stage::Link; - outDiagnostic.severity = Diagnostic::Severity::Info; + outDiagnostic.stage = ArtifactDiagnostic::Stage::Link; + outDiagnostic.severity = ArtifactDiagnostic::Severity::Info; - outDiagnostic.text = UnownedStringSlice(line.begin() + linkPrefix.getLength(), line.end()); + outDiagnostic.text = allocator.allocate(line.begin() + linkPrefix.getLength(), line.end()); return SLANG_OK; } - outDiagnostic.stage = Diagnostic::Stage::Compile; + outDiagnostic.stage = ArtifactDiagnostic::Stage::Compile; const char*const start = line.begin(); const char*const end = line.end(); @@ -385,13 +386,13 @@ static SlangResult _parseVisualStudioLine(const UnownedStringSlice& line, Downst return SLANG_FAIL; } - outDiagnostic.filePath = UnownedStringSlice(start, lineNoStart); - outDiagnostic.fileLine = lineNo; + outDiagnostic.filePath = allocator.allocate(start, lineNoStart); + outDiagnostic.location.line = lineNo; } else { - outDiagnostic.filePath = UnownedStringSlice(start, cur + colonIndex); - outDiagnostic.fileLine = 0; + outDiagnostic.filePath = allocator.allocate(start, cur + colonIndex); + outDiagnostic.location.line = 0; } // Save the remaining text in 'postPath' @@ -417,8 +418,8 @@ static SlangResult _parseVisualStudioLine(const UnownedStringSlice& line, Downst } // Extract the code - outDiagnostic.code = UnownedStringSlice(errorSection.begin() + errorCodeIndex + 1, errorSection.end()); - if (outDiagnostic.code.startsWith(UnownedStringSlice::fromLiteral("LNK"))) + outDiagnostic.code = allocator.allocate(errorSection.begin() + errorCodeIndex + 1, errorSection.end()); + if (asStringSlice(outDiagnostic.code).startsWith(UnownedStringSlice::fromLiteral("LNK"))) { outDiagnostic.stage = Diagnostic::Stage::Link; } @@ -430,16 +431,18 @@ static SlangResult _parseVisualStudioLine(const UnownedStringSlice& line, Downst postError = UnownedStringSlice(postPath.begin() + errorColonIndex + 1, end); } - outDiagnostic.text = postError; + outDiagnostic.text = allocator.allocate(postError); return SLANG_OK; } -/* static */SlangResult VisualStudioCompilerUtil::parseOutput(const ExecuteResult& exeRes, DownstreamDiagnostics& outDiagnostics) +/* static */SlangResult VisualStudioCompilerUtil::parseOutput(const ExecuteResult& exeRes, IArtifactDiagnostics* diagnostics) { - outDiagnostics.reset(); + diagnostics->reset(); - outDiagnostics.rawDiagnostics = exeRes.standardOutput; + diagnostics->setRaw(CharSliceCaster::asTerminatedCharSlice(exeRes.standardOutput)); + + CharSliceAllocator allocator; for (auto line : LineParser(exeRes.standardOutput.getUnownedSlice())) { @@ -448,17 +451,17 @@ static SlangResult _parseVisualStudioLine(const UnownedStringSlice& line, Downst fprintf(stdout, "\n"); #endif - Diagnostic diagnostic; - if (SLANG_SUCCEEDED(_parseVisualStudioLine(line, diagnostic))) + ArtifactDiagnostic diagnostic; + if (SLANG_SUCCEEDED(_parseVisualStudioLine(allocator, line, diagnostic))) { - outDiagnostics.diagnostics.add(diagnostic); + diagnostics->add(diagnostic); } } // if it has a compilation error.. set on output - if (outDiagnostics.has(Diagnostic::Severity::Error)) + if (diagnostics->hasOfAtLeastSeverity(ArtifactDiagnostic::Severity::Error)) { - outDiagnostics.result = SLANG_FAIL; + diagnostics->setResult(SLANG_FAIL); } return SLANG_OK; diff --git a/source/compiler-core/slang-visual-studio-compiler-util.h b/source/compiler-core/slang-visual-studio-compiler-util.h index 6c3011e7c..74d7e6292 100644 --- a/source/compiler-core/slang-visual-studio-compiler-util.h +++ b/source/compiler-core/slang-visual-studio-compiler-util.h @@ -12,7 +12,7 @@ struct VisualStudioCompilerUtil : public DownstreamCompilerBaseUtil /// Calculate Visual Studio family compilers cmdLine arguments from options static SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine); /// Parse Visual Studio exeRes into CPPCompiler::Output - static SlangResult parseOutput(const ExecuteResult& exeRes, DownstreamDiagnostics& outOutput); + static SlangResult parseOutput(const ExecuteResult& exeRes, IArtifactDiagnostics* outOutput); static SlangResult calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath); @@ -29,7 +29,7 @@ public: // CommandLineDownstreamCompiler impl - just forwards to the Util virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) SLANG_OVERRIDE { return Util::calcArgs(options, cmdLine); } - virtual SlangResult parseOutput(const ExecuteResult& exeResult, DownstreamDiagnostics& output) SLANG_OVERRIDE { return Util::parseOutput(exeResult, output); } + virtual SlangResult parseOutput(const ExecuteResult& exeResult, IArtifactDiagnostics* diagnostics) SLANG_OVERRIDE { return Util::parseOutput(exeResult, diagnostics); } virtual SlangResult calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath) SLANG_OVERRIDE { return Util::calcModuleFilePath(options, outPath); } virtual SlangResult calcCompileProducts(const CompileOptions& options, DownstreamProductFlags productFlags, List<String>& outPaths) SLANG_OVERRIDE { return Util::calcCompileProducts(options, productFlags, outPaths); } diff --git a/source/core/slang-common.h b/source/core/slang-common.h index 694162f1d..7fddb067e 100644 --- a/source/core/slang-common.h +++ b/source/core/slang-common.h @@ -13,6 +13,7 @@ namespace Slang { + typedef int32_t Int32; typedef uint32_t UInt32; @@ -67,6 +68,15 @@ namespace Slang v1 = _Move(tmp); } + // Make these interfaces have more convenient names + typedef ISlangCastable ICastable; + typedef ISlangClonable IClonable; + + // Convenience function for using clonable + template <typename T> + SLANG_FORCE_INLINE T* clone(IClonable* clonable) { return (T*)clonable->clone(T::getTypeGuid()); } + + // TODO: Shouldn't these be SLANG_ prefixed? #ifdef _MSC_VER #define UNREACHABLE_RETURN(x) diff --git a/source/core/slang-destroyable.h b/source/core/slang-destroyable.h index 390b16e7c..f2c967071 100644 --- a/source/core/slang-destroyable.h +++ b/source/core/slang-destroyable.h @@ -48,6 +48,21 @@ SLANG_FORCE_INLINE T* as(ICastable* castable) return nullptr; } +// A way to clone an interface (that derives from IClonable) such that it returns an interface +// of the same type. +template <typename T> +SLANG_FORCE_INLINE ComPtr<T> cloneInterface(T* in) +{ + SLANG_ASSERT(in); + // Must be derivable from clonable + IClonable* clonable = in; + // We can clone with the same interface + T* clone = (T*)clonable->clone(T::getTypeGuid()); + // Clone must exist + SLANG_ASSERT(clone); + return ComPtr<T>(clone); +} + } #endif // SLANG_CORE_DESTROYABLE_H diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index d175277c8..a41463ad5 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -20,6 +20,7 @@ #include "../compiler-core/slang-artifact-impl.h" #include "../compiler-core/slang-artifact-util.h" #include "../compiler-core/slang-artifact-associated.h" +#include "../compiler-core/slang-artifact-diagnostic-util.h" // Artifact output #include "slang-artifact-output-util.h" @@ -855,13 +856,12 @@ namespace Slang return true; } - static Severity _getDiagnosticSeverity(DownstreamDiagnostic::Severity severity) + static Severity _getDiagnosticSeverity(ArtifactDiagnostic::Severity severity) { - typedef DownstreamDiagnostic::Severity DownstreamSeverity; switch (severity) { - case DownstreamSeverity::Warning: return Severity::Warning; - case DownstreamSeverity::Info: return Severity::Note; + case ArtifactDiagnostic::Severity::Warning: return Severity::Warning; + case ArtifactDiagnostic::Severity::Info: return Severity::Note; default: return Severity::Error; } } @@ -1077,10 +1077,10 @@ namespace Slang sourceLanguage = (SourceLanguage)TypeConvertUtil::getSourceLanguageFromTarget((SlangCompileTarget)sourceTarget); } - ComPtr<IPostEmitMetadata> metadata; + ComPtr<IArtifactPostEmitMetadata> metadata; if (sourceArtifact) { - metadata = findAssociated<IPostEmitMetadata>(sourceArtifact); + metadata = findAssociated<IArtifactPostEmitMetadata>(sourceArtifact); ComPtr<ISlangBlob> blob; SLANG_RETURN_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::No, blob.writeRef())); @@ -1354,74 +1354,70 @@ namespace Slang } // Compile - RefPtr<DownstreamCompileResult> downstreamCompileResult; + ComPtr<IArtifact> artifact; auto downstreamStartTime = std::chrono::high_resolution_clock::now(); - SLANG_RETURN_ON_FAIL(compiler->compile(options, downstreamCompileResult)); + SLANG_RETURN_ON_FAIL(compiler->compile(options, artifact.writeRef())); auto downstreamElapsedTime = (std::chrono::high_resolution_clock::now() - downstreamStartTime).count() * 0.000000001; getSession()->addDownstreamCompileTime(downstreamElapsedTime); - const auto& diagnostics = downstreamCompileResult->getDiagnostics(); + auto diagnostics = findAssociated<IArtifactDiagnostics>(artifact); - if (diagnostics.diagnostics.getCount()) + if (diagnostics->getCount()) { StringBuilder compilerText; DownstreamCompilerUtil::appendAsText(compiler->getDesc(), compilerText); StringBuilder builder; - for (const auto& diagnostic : diagnostics.diagnostics) + auto const diagnosticCount = diagnostics->getCount(); + for (Index i = 0; i < diagnosticCount; ++i) { + const auto& diagnostic = *diagnostics->getAt(i); + builder.Clear(); const Severity severity = _getDiagnosticSeverity(diagnostic.severity); - if (diagnostic.filePath.getLength() == 0 && diagnostic.fileLine == 0 && severity == Severity::Note) + if (diagnostic.filePath.count == 0 && diagnostic.location.line == 0 && severity == Severity::Note) { // If theres no filePath line number and it's info, output severity and text alone builder << getSeverityName(severity) << " : "; } else { - if (diagnostic.filePath.getLength()) + if (diagnostic.filePath.count) { - builder << diagnostic.filePath; + builder << asStringSlice(diagnostic.filePath); } - if (diagnostic.fileLine) + if (diagnostic.location.line) { - builder << "(" << diagnostic.fileLine <<")"; + builder << "(" << diagnostic.location.line <<")"; } builder << ": "; - if (diagnostic.stage == DownstreamDiagnostic::Stage::Link) + if (diagnostic.stage == ArtifactDiagnostic::Stage::Link) { builder << "link "; } builder << getSeverityName(severity); - builder << " " << diagnostic.code << ": "; + builder << " " << asStringSlice(diagnostic.code) << ": "; } - builder << diagnostic.text; + builder << asStringSlice(diagnostic.text); reportExternalCompileError(compilerText.getBuffer(), severity, SLANG_OK, builder.getUnownedSlice(), sink); } } // If any errors are emitted, then we are done - if (diagnostics.has(DownstreamDiagnostic::Severity::Error)) + if (diagnostics->hasOfAtLeastSeverity(ArtifactDiagnostic::Severity::Error)) { return SLANG_FAIL; } - // Create the artifact that encapsulates the result - auto artifact = ArtifactUtil::createArtifactForCompileTarget(asExternal(target)); - - // Wrap the downstream compile result - auto objRep = new ObjectArtifactRepresentation(DownstreamCompileResult::getTypeGuid(), downstreamCompileResult); - artifact->addRepresentation(objRep); - if (metadata) { artifact->addAssociated(metadata); diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 6e78c82dc..3ec03d0e7 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -837,7 +837,7 @@ Result linkAndOptimizeIR( #endif validateIRModuleIfEnabled(codeGenContext, irModule); - auto metadata = new PostEmitMetadataImpl; + auto metadata = new ArtifactPostEmitMetadata; outLinkedIR.metadata = metadata; collectMetadata(irModule, *metadata); @@ -928,7 +928,7 @@ SlangResult CodeGenContext::emitEntryPointsSourceFromIR(ComPtr<IArtifact>& outAr SLANG_RETURN_ON_FAIL(sourceEmitter->init()); - ComPtr<IPostEmitMetadata> metadata; + ComPtr<IArtifactPostEmitMetadata> metadata; { LinkingAndOptimizationOptions linkingAndOptimizationOptions; diff --git a/source/slang/slang-ir-link.h b/source/slang/slang-ir-link.h index 5fac8dde2..2f255b041 100644 --- a/source/slang/slang-ir-link.h +++ b/source/slang/slang-ir-link.h @@ -11,10 +11,10 @@ namespace Slang struct LinkedIR { - RefPtr<IRModule> module; - IRVarLayout* globalScopeVarLayout; - List<IRFunc*> entryPoints; - ComPtr<IPostEmitMetadata> metadata; + RefPtr<IRModule> module; + IRVarLayout* globalScopeVarLayout; + List<IRFunc*> entryPoints; + ComPtr<IArtifactPostEmitMetadata> metadata; }; diff --git a/source/slang/slang-ir-metadata.cpp b/source/slang/slang-ir-metadata.cpp index b6ab2b922..641c272a2 100644 --- a/source/slang/slang-ir-metadata.cpp +++ b/source/slang/slang-ir-metadata.cpp @@ -39,7 +39,7 @@ static void _insertBinding(List<ShaderBindingRange>& ranges, LayoutResourceKind } // Collects the metadata from the provided IR module, saves it in outMetadata. -void collectMetadata(const IRModule* irModule, PostEmitMetadataImpl& outMetadata) +void collectMetadata(const IRModule* irModule, ArtifactPostEmitMetadata& outMetadata) { // Scan the instructions looking for global resource declarations for (const auto& inst : irModule->getGlobalInsts()) diff --git a/source/slang/slang-ir-metadata.h b/source/slang/slang-ir-metadata.h index f5e3229ae..acc89b7aa 100644 --- a/source/slang/slang-ir-metadata.h +++ b/source/slang/slang-ir-metadata.h @@ -4,9 +4,9 @@ namespace Slang { -class PostEmitMetadataImpl; +class ArtifactPostEmitMetadata; struct IRModule; -void collectMetadata(const IRModule* irModule, PostEmitMetadataImpl& outMetadata); +void collectMetadata(const IRModule* irModule, ArtifactPostEmitMetadata& outMetadata); } diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 1b8ae0d8f..3fce0e6d9 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -2737,7 +2737,7 @@ void Linkage::_diagnoseErrorInImportedModule( { for(auto info = m_modulesBeingImported; info; info = info->next) { - sink->diagnose(info->importLoc, Diagnostics::errorInImportedModule, info->name); + sink->diagnose(info->importLoc, Diagnostics::errorInImportedModule, info->name); } if (!isInLanguageServer()) { @@ -5057,7 +5057,7 @@ SlangResult EndToEndCompileRequest::isParameterLocationUsed(Int entryPointIndex, return SLANG_E_INVALID_ARG; // Find a rep - auto metadata = findAssociated<IPostEmitMetadata>(artifact); + auto metadata = findAssociated<IArtifactPostEmitMetadata>(artifact); if (!metadata) return SLANG_E_NOT_AVAILABLE; diff --git a/tools/slang-test/parse-diagnostic-util.cpp b/tools/slang-test/parse-diagnostic-util.cpp index 552a0924b..c2cc1f010 100644 --- a/tools/slang-test/parse-diagnostic-util.cpp +++ b/tools/slang-test/parse-diagnostic-util.cpp @@ -11,13 +11,13 @@ #include "../../source/core/slang-byte-encode-util.h" #include "../../source/core/slang-char-util.h" +#include "../../source/compiler-core/slang-artifact-diagnostic-util.h" +#include "../../source/compiler-core/slang-artifact-associated-impl.h" #include "../../source/compiler-core/slang-downstream-compiler.h" using namespace Slang; - - -/* static */SlangResult ParseDiagnosticUtil::parseGenericLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic) +/* static */SlangResult ParseDiagnosticUtil::parseGenericLine(CharSliceAllocator& allocator, const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, ArtifactDiagnostic& outDiagnostic) { /* e:\git\somewhere\tests\diagnostics\syntax-error-intrinsic.slang(13): error C2018: unknown character '0x40' */ if (lineSlices.getCount() < 3) @@ -28,29 +28,29 @@ using namespace Slang; { const UnownedStringSlice severityAndCodeSlice = lineSlices[1].trim(); // Get the code - outDiagnostic.code = StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 1).trim(); + outDiagnostic.code = allocator.allocate(StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 1).trim()); const UnownedStringSlice severitySlice = StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 0); - outDiagnostic.severity = DownstreamDiagnostic::Severity::Error; + outDiagnostic.severity = ArtifactDiagnostic::Severity::Error; if (severitySlice == UnownedStringSlice::fromLiteral("warning")) { - outDiagnostic.severity = DownstreamDiagnostic::Severity::Warning; + outDiagnostic.severity = ArtifactDiagnostic::Severity::Warning; } else if (severitySlice == UnownedStringSlice::fromLiteral("info")) { - outDiagnostic.severity = DownstreamDiagnostic::Severity::Info; + outDiagnostic.severity = ArtifactDiagnostic::Severity::Info; } } // Get the location info - SLANG_RETURN_ON_FAIL(DownstreamDiagnostic::splitPathLocation(lineSlices[0], outDiagnostic)); + SLANG_RETURN_ON_FAIL(ArtifactDiagnosticUtil::splitPathLocation(allocator, lineSlices[0], outDiagnostic)); - outDiagnostic.text = UnownedStringSlice(lineSlices[2].begin(), line.end()); + outDiagnostic.text = allocator.allocate(lineSlices[2].begin(), line.end()); return SLANG_OK; } -static SlangResult _getSlangDiagnosticSeverity(const UnownedStringSlice& inText, DownstreamDiagnostic::Severity& outSeverity, Int& outCode) +static SlangResult _getSlangDiagnosticSeverity(const UnownedStringSlice& inText, ArtifactDiagnostic::Severity& outSeverity, Int& outCode) { UnownedStringSlice text(inText.trim()); @@ -79,9 +79,9 @@ static SlangResult _getSlangDiagnosticSeverity(const UnownedStringSlice& inText, switch (index) { case -1: return SLANG_FAIL; - case 0: outSeverity = DownstreamDiagnostic::Severity::Info; break; - case 1: outSeverity = DownstreamDiagnostic::Severity::Warning; break; - default: outSeverity = DownstreamDiagnostic::Severity::Error; break; + case 0: outSeverity = ArtifactDiagnostic::Severity::Info; break; + case 1: outSeverity = ArtifactDiagnostic::Severity::Warning; break; + default: outSeverity = ArtifactDiagnostic::Severity::Error; break; } outCode = 0; @@ -108,12 +108,12 @@ static bool _isSlangDiagnostic(const UnownedStringSlice& line) // Extract the type/code slice UnownedStringSlice typeSlice = StringUtil::getAtInSplit(line, ':', typeIndex); - DownstreamDiagnostic::Severity type; + ArtifactDiagnostic::Severity type; Int code; return SLANG_SUCCEEDED(_getSlangDiagnosticSeverity(typeSlice, type, code)); } -/* static */SlangResult ParseDiagnosticUtil::parseSlangLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic) +/* static */SlangResult ParseDiagnosticUtil::parseSlangLine(CharSliceAllocator& allocator, const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, ArtifactDiagnostic& outDiagnostic) { /* tests/diagnostics/accessors.slang(11): error 31101: accessors other than 'set' must not have parameters @@ -125,7 +125,7 @@ static bool _isSlangDiagnostic(const UnownedStringSlice& line) return SLANG_FAIL; } - SLANG_RETURN_ON_FAIL(DownstreamDiagnostic::splitPathLocation(lineSlices[0], outDiagnostic)); + SLANG_RETURN_ON_FAIL(ArtifactDiagnosticUtil::splitPathLocation(allocator, lineSlices[0], outDiagnostic)); Int code; SLANG_RETURN_ON_FAIL(_getSlangDiagnosticSeverity(lineSlices[1], outDiagnostic.severity, code)); @@ -133,10 +133,10 @@ static bool _isSlangDiagnostic(const UnownedStringSlice& line) { StringBuilder buf; buf << code; - outDiagnostic.code = buf.ProduceString(); + outDiagnostic.code = allocator.allocate(buf); } - outDiagnostic.text = UnownedStringSlice(lineSlices[2].begin(), line.end()); + outDiagnostic.text = allocator.allocate(lineSlices[2].begin(), line.end()); return SLANG_OK; } @@ -251,12 +251,11 @@ static bool _isWhitespace(const UnownedStringSlice& slice) return true; } -/* static */SlangResult ParseDiagnosticUtil::parseDiagnostics(const UnownedStringSlice& inText, List<DownstreamDiagnostic>& outDiagnostics) +/* static */SlangResult ParseDiagnosticUtil::parseDiagnostics(const UnownedStringSlice& inText, IArtifactDiagnostics* diagnostics) { if (_isWhitespace(inText)) { // If it's empty, then there are no diagnostics to add. - outDiagnostics.clear(); return SLANG_OK; } @@ -274,10 +273,10 @@ static bool _isWhitespace(const UnownedStringSlice& slice) // For now we assume no prefix. } - return parseDiagnostics(inText, compilerIdentity, linePrefix, outDiagnostics); + return parseDiagnostics(inText, compilerIdentity, linePrefix, diagnostics); } -/* static */SlangResult ParseDiagnosticUtil::parseDiagnostics(const UnownedStringSlice& inText, const CompilerIdentity& compilerIdentity, const UnownedStringSlice& linePrefix, List<DownstreamDiagnostic>& outDiagnostics) +/* static */SlangResult ParseDiagnosticUtil::parseDiagnostics(const UnownedStringSlice& inText, const CompilerIdentity& compilerIdentity, const UnownedStringSlice& linePrefix, IArtifactDiagnostics* diagnostics) { auto lineParser = getLineParser(compilerIdentity); if (!lineParser) @@ -287,6 +286,8 @@ static bool _isWhitespace(const UnownedStringSlice& slice) List<UnownedStringSlice> splitLine; + CharSliceAllocator allocator; + UnownedStringSlice text(inText), line; while (StringUtil::extractLine(text, line)) { @@ -307,23 +308,23 @@ static bool _isWhitespace(const UnownedStringSlice& slice) // If we don't have a valid split then just assume it's a note if (!isValidSplit) { - DownstreamDiagnostics::addNote(line, outDiagnostics); + diagnostics->maybeAddNote(asCharSlice(line)); continue; } - DownstreamDiagnostic diagnostic; - diagnostic.severity = DownstreamDiagnostic::Severity::Error; - diagnostic.stage = DownstreamDiagnostic::Stage::Compile; - diagnostic.fileLine = 0; + ArtifactDiagnostic diagnostic; + diagnostic.severity = ArtifactDiagnostic::Severity::Error; + diagnostic.stage = ArtifactDiagnostic::Stage::Compile; + diagnostic.location.line = 0; - if (SLANG_SUCCEEDED(lineParser(line, splitLine, diagnostic))) + if (SLANG_SUCCEEDED(lineParser(allocator, line, splitLine, diagnostic))) { - outDiagnostics.add(diagnostic); + diagnostics->add(diagnostic); } else { // If couldn't parse, just add as a note - DownstreamDiagnostics::addNote(line, outDiagnostics); + ArtifactDiagnosticUtil::maybeAddNote(line, diagnostics); } } @@ -427,7 +428,9 @@ static UnownedStringSlice _getEquals(const UnownedStringSlice& in) /* static */bool ParseDiagnosticUtil::areEqual(const UnownedStringSlice& a, const UnownedStringSlice& b, EqualityFlags flags) { - List<DownstreamDiagnostic> diagsA, diagsB; + auto diagsA = ArtifactDiagnostics::create(); + auto diagsB = ArtifactDiagnostics::create(); + SlangResult resA = ParseDiagnosticUtil::parseDiagnostics(a, diagsA); SlangResult resB = ParseDiagnosticUtil::parseDiagnostics(b, diagsB); @@ -448,18 +451,21 @@ static UnownedStringSlice _getEquals(const UnownedStringSlice& in) // Must have both succeeded, and have the same amount of lines if (SLANG_SUCCEEDED(resA) && SLANG_SUCCEEDED(resB) && - diagsA.getCount() == diagsB.getCount()) + diagsA->getCount() == diagsB->getCount()) { - for (Index i = 0; i < diagsA.getCount(); ++i) + const auto count = diagsA->getCount(); + for (Index i = 0; i < count; ++i) { - DownstreamDiagnostic diagA = diagsA[i]; - DownstreamDiagnostic diagB = diagsB[i]; + ArtifactDiagnostic diagA = *diagsA->getAt(i); + ArtifactDiagnostic diagB = *diagsB->getAt(i); // Check if we need to ignore line numbers if (flags & EqualityFlag::IgnoreLineNos) { - diagA.fileLine = 0; - diagB.fileLine = 0; + const ArtifactDiagnostic::Location loc; + + diagA.location = loc; + diagB.location = loc; } if (diagA != diagB) diff --git a/tools/slang-test/parse-diagnostic-util.h b/tools/slang-test/parse-diagnostic-util.h index b9f81bfe8..eb631f1fa 100644 --- a/tools/slang-test/parse-diagnostic-util.h +++ b/tools/slang-test/parse-diagnostic-util.h @@ -8,6 +8,8 @@ #include "../../source/compiler-core/slang-downstream-compiler.h" +#include "../../source/compiler-core/slang-artifact-diagnostic-util.h" + #include "../../slang-com-ptr.h" struct ParseDiagnosticUtil @@ -55,23 +57,23 @@ struct ParseDiagnosticUtil }; }; - typedef SlangResult (*LineParser)(const Slang::UnownedStringSlice& line, Slang::List<Slang::UnownedStringSlice>& lineSlices, Slang::DownstreamDiagnostic& outDiagnostic); + typedef SlangResult (*LineParser)(Slang::CharSliceAllocator& allocator, const Slang::UnownedStringSlice& line, Slang::List<Slang::UnownedStringSlice>& lineSlices, Slang::ArtifactDiagnostic& outDiagnostic); /// Given a compiler identity returns a line parsing function. static LineParser getLineParser(const CompilerIdentity& compilerIdentity); /// For a 'generic' (as in uses DownstreamCompiler mechanism) line parsing - static SlangResult parseGenericLine(const Slang::UnownedStringSlice& line, Slang::List<Slang::UnownedStringSlice>& lineSlices, Slang::DownstreamDiagnostic& outDiagnostic); + static SlangResult parseGenericLine(Slang::CharSliceAllocator& allocator, const Slang::UnownedStringSlice& line, Slang::List<Slang::UnownedStringSlice>& lineSlices, Slang::ArtifactDiagnostic& outDiagnostic); /// For parsing diagnostics from Slang - static SlangResult parseSlangLine(const Slang::UnownedStringSlice& line, Slang::List<Slang::UnownedStringSlice>& lineSlices, Slang::DownstreamDiagnostic& outDiagnostic); + static SlangResult parseSlangLine(Slang::CharSliceAllocator& allocator, const Slang::UnownedStringSlice& line, Slang::List<Slang::UnownedStringSlice>& lineSlices, Slang::ArtifactDiagnostic& outDiagnostic); /// Parse diagnostics into output text - static SlangResult parseDiagnostics(const Slang::UnownedStringSlice& inText, Slang::List<Slang::DownstreamDiagnostic>& outDiagnostics); + static SlangResult parseDiagnostics(const Slang::UnownedStringSlice& inText, Slang::IArtifactDiagnostics* diagnostics); /// Parse diagnostics with known compiler identity. /// If the prefix is empty, it is assumed there is no prefix and it won't be checked. - static SlangResult parseDiagnostics(const Slang::UnownedStringSlice& inText, const CompilerIdentity& identity, const Slang::UnownedStringSlice& prefix, Slang::List<Slang::DownstreamDiagnostic>& outDiagnostics); + static SlangResult parseDiagnostics(const Slang::UnownedStringSlice& inText, const CompilerIdentity& identity, const Slang::UnownedStringSlice& prefix, Slang::IArtifactDiagnostics* diagnostics); /// Given the file output style used by tests, get components of the output into Diagnostic static SlangResult parseOutputInfo(const Slang::UnownedStringSlice& in, OutputInfo& out); diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp index 8e6e6f3e1..af7ca1f83 100644 --- a/tools/slang-test/slang-test-main.cpp +++ b/tools/slang-test/slang-test-main.cpp @@ -33,6 +33,8 @@ #include "../../source/compiler-core/slang-nvrtc-compiler.h" #include "../../source/compiler-core/slang-language-server-protocol.h" +#include "../../source/compiler-core/slang-artifact-associated-impl.h" + #define STB_IMAGE_IMPLEMENTATION #include "external/stb/stb_image.h" @@ -1904,8 +1906,8 @@ TestResult runSimpleLineTest(TestContext* context, TestInput& input) } // Parse all the diagnostics so we can extract line numbers - List<DownstreamDiagnostic> diagnostics; - if (SLANG_FAILED(ParseDiagnosticUtil::parseDiagnostics(exeRes.standardError.getUnownedSlice(), diagnostics)) || diagnostics.getCount() <= 0) + auto diagnostics = ArtifactDiagnostics::create(); + if (SLANG_FAILED(ParseDiagnosticUtil::parseDiagnostics(exeRes.standardError.getUnownedSlice(), diagnostics)) || diagnostics->getCount() <= 0) { // Write out the diagnostics which couldn't be parsed. @@ -1917,9 +1919,9 @@ TestResult runSimpleLineTest(TestContext* context, TestInput& input) StringBuilder actualOutput; - if (diagnostics.getCount() > 0) + if (diagnostics->getCount() > 0) { - actualOutput << diagnostics[0].fileLine << "\n"; + actualOutput << diagnostics->getAt(0)->location.line << "\n"; } else { @@ -2136,18 +2138,18 @@ String getExpectedOutput(String const& outputStem) return expectedOutput; } -static String _calcSummary(const DownstreamDiagnostics& inOutput) +static String _calcSummary(IArtifactDiagnostics* inDiagnostics) { - DownstreamDiagnostics output(inOutput); - + auto diagnostics = cloneInterface(inDiagnostics); + // We only want to analyze errors for now - output.removeBySeverity(DownstreamDiagnostic::Severity::Info); - output.removeBySeverity(DownstreamDiagnostic::Severity::Warning); + diagnostics->removeBySeverity(ArtifactDiagnostic::Severity::Info); + diagnostics->removeBySeverity(ArtifactDiagnostic::Severity::Warning); - StringBuilder builder; + ComPtr<ISlangBlob> summary; + diagnostics->calcSimplifiedSummary(summary.writeRef()); - output.appendSimplifiedSummary(builder); - return builder; + return StringUtil::getString(summary); } static TestResult runCPPCompilerCompile(TestContext* context, TestInput& input) @@ -2236,15 +2238,15 @@ static TestResult runCPPCompilerSharedLibrary(TestContext* context, TestInput& i options.includePaths.add("."); - RefPtr<DownstreamCompileResult> compileResult; - if (SLANG_FAILED(compiler->compile(options, compileResult))) + ComPtr<IArtifact> artifact; + if (SLANG_FAILED(compiler->compile(options, artifact.writeRef()))) { return TestResult::Fail; } - const auto& diagnostics = compileResult->getDiagnostics(); + auto diagnostics = findAssociated<IArtifactDiagnostics>(artifact); - if (SLANG_FAILED(diagnostics.result)) + if (diagnostics && SLANG_FAILED(diagnostics->getResult())) { // Compilation failed String actualOutput = _calcSummary(diagnostics); @@ -2353,18 +2355,18 @@ static TestResult runCPPCompilerExecute(TestContext* context, TestInput& input) options.sourceFiles.add(filePath); options.modulePath = modulePath; - RefPtr<DownstreamCompileResult> compileResult; - if (SLANG_FAILED(compiler->compile(options, compileResult))) + ComPtr<IArtifact> artifact; + if (SLANG_FAILED(compiler->compile(options, artifact.writeRef()))) { return TestResult::Fail; } String actualOutput; - const auto& diagnostics = compileResult->getDiagnostics(); + auto diagnostics = findAssociated<IArtifactDiagnostics>(artifact); // If the actual compilation failed, then the output will be the summary - if (SLANG_FAILED(diagnostics.result)) + if (diagnostics && SLANG_FAILED(diagnostics->getResult())) { actualOutput = _calcSummary(diagnostics); } |
