Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8922141
Fix SLANG_ENABLE_ASAN CMake option
ncelikNV Nov 11, 2025
4dae658
Fix formatting
ncelikNV Nov 12, 2025
7e8a478
Fix GCC -Wstring-compare warning (which I couldn't write a minimal re…
ncelikNV Nov 12, 2025
53b5d33
Fix MSVC warning
ncelikNV Nov 12, 2025
ffd7a0e
Maybe fix macOS ld error
ncelikNV Nov 12, 2025
9fe3e02
Remove own TODO/NOTE comments
ncelikNV Nov 12, 2025
506d457
Fix Clang unused variable warning
ncelikNV Nov 12, 2025
817f6db
Fix MSVC warning
ncelikNV Nov 12, 2025
0a30070
Revert `#if 0` cleanups
ncelikNV Nov 17, 2025
3d46bc2
Re-enable SLANG_UNALIGNED_ACCESS and fix slang-byte-encode-util.cpp UB
ncelikNV Nov 17, 2025
d688ef3
Fix logical right shift being used instead of arithmetic right shift
ncelikNV Nov 18, 2025
bc306b7
Fix UIntSet::clear() call sites instead of adding non-null buffer check
ncelikNV Nov 18, 2025
6261017
Disable Clang optimizations for `Session::get*LibraryCode()` functions
ncelikNV Nov 19, 2025
fa1982c
Merge branch 'master' into fix-slang-enable-asan
ncelikNV Nov 19, 2025
39971df
Fix CommandLineDownstreamCompiler::compile()
ncelikNV Nov 19, 2025
b4a3193
Fix MSVC shadowing warning
ncelikNV Nov 21, 2025
5464944
Silence MSVC warning: "unary minus operator applied to unsigned type,…
ncelikNV Nov 21, 2025
6076e54
Document that these functions are only called once
ncelikNV Nov 21, 2025
1d870d6
Merge branch 'fix-slang-enable-asan' into fix-slang-enable-asan-1
ncelikNV Nov 24, 2025
799a19a
Merge branch 'fix-clang-release-build-times' into fix-slang-enable-as…
ncelikNV Nov 24, 2025
03c725f
Fix `SLANG_ENABLE_ASAN` CMake option
ncelikNV Nov 24, 2025
f3630e2
Minor refactorings
ncelikNV Nov 24, 2025
d33b400
Emit CMake FATAL_ERROR instead of warning if the C++ compiler is unsu…
ncelikNV Nov 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions cmake/CompilerFlags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -214,19 +214,27 @@ function(set_default_compile_options target)
)

if(SLANG_ENABLE_ASAN)
add_supported_cxx_flags(
${target}
PRIVATE
/fsanitize=address
-fsanitize=address
)
add_supported_cxx_linker_flags(
${target}
BEFORE
PUBLIC
/INCREMENTAL:NO
-fsanitize=address
)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# Clang defaults to statically linking the sanitizer runtime (except on macOS/Darwin),
# which is not compatible with `-Wl,--no-undefined`, so we need to use dynamic linking
# instead (`-shared-libsan`).
target_compile_options(
${target}
PRIVATE -fsanitize=address -shared-libsan
)
target_link_options(
${target}
PUBLIC -fsanitize=address -shared-libsan
)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(${target} PRIVATE -fsanitize=address)
target_link_options(${target} PUBLIC -fsanitize=address)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(${target} PRIVATE /fsanitize=address)
target_link_options(${target} PRIVATE /INCREMENTAL:NO)
else()
message(FATAL_ERROR "SLANG_ENABLE_ASAN: unsupported C++ compiler")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be better to raise a FATAL_ERROR (which stops CMake generation) as users might not notice a warning. Since SLANG_ENABLE_ASAN defaults to OFF I think it's safe to assume that it being ON implies the user really doesn't want Slang being built without sanitizers.

endif()
endif()

if(SLANG_ENABLE_COVERAGE)
Expand Down
128 changes: 105 additions & 23 deletions source/compiler-core/slang-downstream-compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,30 @@ SlangResult CommandLineDownstreamCompiler::compile(
if (!isVersionCompatible(inOptions))
{
// Not possible to compile with this version of the interface.
// TODO: Fix other `IDownstreamCompiler::compile` implementations not always writing to
// `outArtifact` when returning early.
const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(SLANG_TARGET_UNKNOWN);
auto artifact = ArtifactUtil::createArtifact(targetDesc);
*outArtifact = artifact.detach();
return SLANG_E_NOT_IMPLEMENTED;
}

CompileOptions options = getCompatibleVersion(&inOptions);
const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType);

// Copy the command line options
CommandLine cmdLine(m_cmdLine);
// Create the result artifact
auto resultArtifact = ArtifactUtil::createArtifact(targetDesc);

// Work out the ArtifactDesc
const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType);
// Create the diagnostics
auto diagnostics = ArtifactDiagnostics::create();
ArtifactUtil::addAssociated(resultArtifact, diagnostics);

// If Slang was built with Clang or GCC and sanitizers were enabled, the same `-fsanitize=...`
// flag must be passed when linking an executable or shared library with a Slang library, or
// linking will fail. We can't instrument C++ generated from Slang code with sanitizers as they
// might report errors that can't be fixed, so we separate compilation and linking into two
// commands to enable sanitizers only during linking.
bool shouldSeparateCompileAndLink = options.targetType != SLANG_OBJECT_CODE;

auto helper = DefaultArtifactHelper::getSingleton();

Expand All @@ -95,8 +109,13 @@ SlangResult CommandLineDownstreamCompiler::compile(
{
// We could use the path to the source, or use the source name/paths as defined on the
// artifact For now we just go with a lock file based on "slang-generated".
SLANG_RETURN_ON_FAIL(
helper->createLockFile(asCharSlice(toSlice("slang-generated")), lockFile.writeRef()));
if (SLANG_FAILED(helper->createLockFile(
asCharSlice(toSlice("slang-generated")),
lockFile.writeRef())))
{
*outArtifact = resultArtifact.detach();
return SLANG_FAIL;
}

auto lockArtifact = Artifact::create(
ArtifactDesc::make(ArtifactKind::Base, ArtifactPayload::Lock, ArtifactStyle::None));
Expand All @@ -110,17 +129,83 @@ SlangResult CommandLineDownstreamCompiler::compile(
options.modulePath = SliceUtil::asTerminatedCharSlice(modulePath);
}

// Compile stage if executable or library target: compile source to object code

ComPtr<IArtifact> objectArtifact;

if (shouldSeparateCompileAndLink)
{
CompileOptions compileOptions = options;
compileOptions.targetType = SLANG_OBJECT_CODE;

CommandLine compileCmdLine(m_cmdLine);
if (SLANG_FAILED(calcArgs(compileOptions, compileCmdLine)))
{
*outArtifact = resultArtifact.detach();
return SLANG_FAIL;
}

List<ComPtr<IArtifact>> compileArtifacts;
if (SLANG_FAILED(calcCompileProducts(
compileOptions,
DownstreamProductFlag::All,
lockFile,
compileArtifacts)))
{
*outArtifact = resultArtifact.detach();
return SLANG_FAIL;
}

// There should only be one object file (.o/.obj) as artifact
SLANG_ASSERT(compileArtifacts.getCount() == 1);
SLANG_ASSERT(compileArtifacts[0]->getDesc().kind == ArtifactKind::ObjectCode);
objectArtifact = compileArtifacts[0];

ExecuteResult compileResult;
if (SLANG_FAILED(ProcessUtil::execute(compileCmdLine, compileResult)) ||
SLANG_FAILED(parseOutput(compileResult, diagnostics)))
{
*outArtifact = resultArtifact.detach();
return SLANG_FAIL;
}

// If compilation failed, return the diagnostics
if (compileResult.resultCode != 0 || !objectArtifact->exists())
{
*outArtifact = resultArtifact.detach();
return SLANG_FAIL;
}
}

// Link stage if executable or library target, or single-stage compile if object code target

CommandLine cmdLine(m_cmdLine);

if (shouldSeparateCompileAndLink)
{
// Pass compiled object to linker
options.sourceArtifacts = makeSlice(objectArtifact.readRef(), 1);
}

// Append command line args to the end of cmdLine using the target specific function for the
// specified options
SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine));
if (SLANG_FAILED(calcArgs(options, cmdLine)))
{
*outArtifact = resultArtifact.detach();
return SLANG_FAIL;
}

// The 'productArtifact' is the main product produced from the compilation - the
// executable/sharedlibrary/object etc
ComPtr<IArtifact> productArtifact;
{
List<ComPtr<IArtifact>> artifacts;
SLANG_RETURN_ON_FAIL(
calcCompileProducts(options, DownstreamProductFlag::All, lockFile, artifacts));
if (SLANG_FAILED(
calcCompileProducts(options, DownstreamProductFlag::All, lockFile, artifacts)))
{
*outArtifact = resultArtifact.detach();
return SLANG_FAIL;
}

for (IArtifact* artifact : artifacts)
{
Expand All @@ -139,6 +224,7 @@ SlangResult CommandLineDownstreamCompiler::compile(
// Somethings gone wrong if we don't find the main artifact
if (!productArtifact)
{
*outArtifact = resultArtifact.detach();
return SLANG_FAIL;
}

Expand All @@ -152,7 +238,13 @@ SlangResult CommandLineDownstreamCompiler::compile(
}
#endif

SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes));
if (SLANG_FAILED(ProcessUtil::execute(cmdLine, exeRes)) ||
SLANG_FAILED(parseOutput(exeRes, diagnostics)))
{
// If the process failed or the output parsing failed, return the diagnostics
*outArtifact = resultArtifact.detach();
return SLANG_FAIL;
}

#if 0
{
Expand Down Expand Up @@ -209,23 +301,13 @@ SlangResult CommandLineDownstreamCompiler::compile(
}
}

// Create the result artifact
auto artifact = ArtifactUtil::createArtifact(targetDesc);

// Createa the diagnostics
auto diagnostics = ArtifactDiagnostics::create();

SLANG_RETURN_ON_FAIL(parseOutput(exeRes, diagnostics));

ArtifactUtil::addAssociated(artifact, diagnostics);

// Find the rep from the 'main' artifact, we'll just use the same representation on the output
// artifact. Sharing is desirable, because the rep owns the file.
if (auto fileRep = productArtifact
? findRepresentation<IOSFileArtifactRepresentation>(productArtifact)
: nullptr)
{
artifact->addRepresentation(fileRep);
resultArtifact->addRepresentation(fileRep);
}

// Add the artifact list if there is anything in it
Expand All @@ -242,10 +324,10 @@ SlangResult CommandLineDownstreamCompiler::compile(

artifactContainer->setChildren(slice.data, slice.count);

artifact->addAssociated(artifactContainer);
resultArtifact->addAssociated(artifactContainer);
}

*outArtifact = artifact.detach();
*outArtifact = resultArtifact.detach();
return SLANG_OK;
}

Expand Down
49 changes: 35 additions & 14 deletions source/compiler-core/slang-gcc-compiler-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,7 @@ static SlangResult _parseGCCFamilyLine(

SliceAllocator allocator;

diagnostics->reset();
diagnostics->setRaw(SliceUtil::asCharSlice(exeRes.standardError));
diagnostics->appendRaw(SliceUtil::asCharSlice(exeRes.standardError));
Copy link
Contributor Author

@ncelikNV ncelikNV Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since CommandLineDownstreamCompiler::compile now splits compilation and linking into two commands, we need to be able to combine multiple commands' output into the same diagnostics object. Note that parseOutput is only ever called on a newly created diagnostics object (even without this PR's changes), so there was no need to call diagnostics->reset() here.


// 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
Expand Down Expand Up @@ -603,12 +602,6 @@ static SlangResult _parseGCCFamilyLine(
{
// Shared library
cmdLine.addArg("-shared");

if (PlatformUtil::isFamily(PlatformFamily::Unix, platformKind))
{
// Position independent
cmdLine.addArg("-fPIC");
}
break;
}
case SLANG_HOST_EXECUTABLE:
Expand All @@ -620,12 +613,33 @@ static SlangResult _parseGCCFamilyLine(
{
// Don't link, just produce object file
cmdLine.addArg("-c");

break;
}
default:
break;
}

if (PlatformUtil::isFamily(PlatformFamily::Unix, platformKind))
{
// Position independent
cmdLine.addArg("-fPIC");
}
Comment on lines +623 to +627
Copy link
Contributor Author

@ncelikNV ncelikNV Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial discussion: https://github.com/shader-slang/slang/pull/8980/files#r2528348258.

GCC used to emit the following warning when using -fPIC on Windows until GCC 6.1 (released in 2016):

-fPIC ignored for target (all code is position independent)

See gcc-mirror/gcc@0a1d992. I assume that's why this was restricted to PlatformFamily::Unix. The commit that added this restriction is from 2019 (~3 years after GCC 6.1's release): ea20066.


#if defined(__has_feature)
#if __has_feature(address_sanitizer)
if (options.targetType != SLANG_OBJECT_CODE)
{
#if SLANG_CLANG || SLANG_GCC
cmdLine.addArg("-fsanitize=address");
#endif
#if SLANG_CLANG
cmdLine.addArg("-shared-libsan");
#endif
}
#endif
#endif

// Add defines
for (const auto& define : options.defines)
{
Expand Down Expand Up @@ -711,13 +725,17 @@ static SlangResult _parseGCCFamilyLine(
const UnownedStringSlice path(fileRep->getPath());
libPathPool.add(Path::getParentDirectory(path));

cmdLine.addPrefixPathArg(
"-l",
ArtifactDescUtil::getBaseNameFromPath(artifact->getDesc(), path));
if (options.targetType != SLANG_OBJECT_CODE)
{
cmdLine.addPrefixPathArg(
"-l",
ArtifactDescUtil::getBaseNameFromPath(artifact->getDesc(), path));
}
}
}

if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP &&
options.targetType != SLANG_OBJECT_CODE &&
!PlatformUtil::isFamily(PlatformFamily::Windows, platformKind))
{
// Make STD libs available
Expand All @@ -728,9 +746,12 @@ static SlangResult _parseGCCFamilyLine(

for (const auto& libPath : libPathPool.getAdded())
{
// Note that any escaping of the path is handled in the ProcessUtil::
cmdLine.addArg("-L");
cmdLine.addArg(libPath);
if (options.targetType != SLANG_OBJECT_CODE)
{
// Note that any escaping of the path is handled in the ProcessUtil::
cmdLine.addArg("-L");
cmdLine.addArg(libPath);
}
cmdLine.addArg("-F");
cmdLine.addArg(libPath);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,9 +502,7 @@ static SlangResult _parseVisualStudioLine(
const ExecuteResult& exeRes,
IArtifactDiagnostics* diagnostics)
{
diagnostics->reset();

diagnostics->setRaw(SliceUtil::asTerminatedCharSlice(exeRes.standardOutput));
diagnostics->appendRaw(SliceUtil::asTerminatedCharSlice(exeRes.standardOutput));

SliceAllocator allocator;

Expand Down
12 changes: 10 additions & 2 deletions source/core/slang-string.h
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,11 @@ class SLANG_RT_API String
friend class StringBuilder;

private:
char* getData() const { return m_buffer ? m_buffer->getData() : (char*)""; }
char* getData() const
{
static char empty[] = "";
return m_buffer ? m_buffer->getData() : empty;
}
Comment on lines -470 to +474
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.



void ensureUniqueStorageWithCapacity(Index capacity);
Expand Down Expand Up @@ -658,7 +662,11 @@ class SLANG_RT_API String
#endif
}
}
bool operator==(const char* strbuffer) const { return (strcmp(begin(), strbuffer) == 0); }
bool operator==(const char* strbuffer) const
{
const char* volatile b = begin();
return (strcmp(b, strbuffer) == 0);
}
Comment on lines -661 to +669
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


bool operator==(const String& str) const { return (strcmp(begin(), str.begin()) == 0); }
bool operator!=(const char* strbuffer) const { return (strcmp(begin(), strbuffer) != 0); }
Expand Down
Loading
Loading