Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions docs/command-line-slangc-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,14 @@ all - Treat all warnings as errors.
Disable specific warning ids.


<a id="wall"></a>
### -Wall, -Wextra, -Wpedantic

**-Wall | -Wextra | -Wpedantic**

Comment thread
expipiplus1 marked this conversation as resolved.
Enable the corresponding group of opt-in warnings (additive).


Comment thread
expipiplus1 marked this conversation as resolved.
<a id="w"></a>
### -W

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

// A vertex shader with no SV_Position output triggers W38052.

//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK,non-exhaustive):-target hlsl -entry main -stage vertex -profile sm_5_0
//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK,non-exhaustive):-Wpedantic -target hlsl -entry main -stage vertex -profile sm_5_0
Comment thread
expipiplus1 marked this conversation as resolved.
Comment thread
expipiplus1 marked this conversation as resolved.

[shader("vertex")]
float4 main() : COLOR
Expand Down
1 change: 1 addition & 0 deletions docs/user-guide/08-compiling.md
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,7 @@ meanings of their `CompilerOptionValue` encodings.
| DisableWarnings | Specifies a list of warnings to disable. `stringValue0` encodes comma separated list of warning codes or names. |
| EnableWarning | Specifies a list of warnings to enable. `stringValue0` encodes comma separated list of warning codes or names. |
| DisableWarning | Specify a warning to disable. `stringValue0` encodes the warning code or name. |
| WarningLevel | Enable a group of opt-in warnings, modeled on clang/gcc. `intValue0` encodes a `SlangWarningLevel` group (`SLANG_WARNING_LEVEL_ALL`/`_EXTRA`/`_PEDANTIC`; `SLANG_WARNING_LEVEL_DEFAULT` is the always-on group and is a no-op here). Repeatable and additive, matching the `-Wall`/`-Wextra`/`-Wpedantic` command-line flags. The groups are independent (not nested): `extra` is on by default while `pedantic` is off by default, and warnings in the always-on default group are unaffected. |
| ReportDownstreamTime | Turn on/off downstream compilation time report. `intValue0` encodes a bool value for the setting. |
| ReportPerfBenchmark | Turn on/off reporting of time spent in different parts of the compiler. `intValue0` encodes a bool value for the setting. |
| SkipSPIRVValidation | Specifies whether or not to skip the validation step after emitting SPIR-V. `intValue0` encodes a bool value for the setting. |
Expand Down
19 changes: 19 additions & 0 deletions include/slang.h
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,20 @@ typedef uint32_t SlangSizeT;
*/
};

/* A warning "level" (group), modeled on the clang/gcc -Wall/-Wextra/-Wpedantic
groups. Each group is enabled independently: a warning tagged with a group is
emitted only when that group has been enabled, while warnings in the implicit
Default group are always emitted. */
typedef int SlangWarningLevelIntegral;
enum SlangWarningLevel : SlangWarningLevelIntegral
{
SLANG_WARNING_LEVEL_DEFAULT = 0, /**< Always emitted; this is the baseline group and is not
something a caller enables explicitly. */
SLANG_WARNING_LEVEL_ALL = 1, /**< Warnings enabled by -Wall. */
SLANG_WARNING_LEVEL_EXTRA = 2, /**< Warnings enabled by -Wextra. */
SLANG_WARNING_LEVEL_PEDANTIC = 3, /**< Warnings enabled by -Wpedantic. */
};

Comment thread
expipiplus1 marked this conversation as resolved.
typedef int SlangDiagnosticFlags;
enum
{
Expand Down Expand Up @@ -1217,6 +1231,11 @@ typedef uint32_t SlangSizeT;
// stride. Opt-in; mutually exclusive with a non-zero
// `-spirv-resource-heap-stride` (combining the two is an error).

// intValue0: a SlangWarningLevel group to enable (e.g. SLANG_WARNING_LEVEL_PEDANTIC).
// Repeatable: enabling multiple groups is additive, matching how -Wall/-Wextra/-Wpedantic
// combine on the command line. CLI spellings: -Wall, -Wextra, -Wpedantic.
WarningLevel = 155,

// Do not assign an explicit value to CountOf. It must remain one past the last option,
// which it derives implicitly from the preceding (highest-valued) enumerator.
CountOf,
Expand Down
15 changes: 13 additions & 2 deletions source/compiler-core/slang-diagnostic-sink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,13 @@ Severity DiagnosticSink::getEffectiveMessageSeverity(
if (effectiveSeverity < Severity::Error || *pSeverityOverride >= effectiveSeverity)
effectiveSeverity = *pSeverityOverride;
}
else if (effectiveSeverity == Severity::Warning && !isWarningLevelEnabled(info.level))
{
// The warning belongs to an opt-in group (-Wall/-Wextra/-Wpedantic) that has not been
// enabled, so it is suppressed. An explicit per-id override (-W<name>/-Wno-<name>) takes
// precedence over this group gating, which is why it lives in the `else` branch.
effectiveSeverity = Severity::Disable;
}

if (isFlagSet(Flag::TreatWarningsAsErrors) && effectiveSeverity == Severity::Warning)
effectiveSeverity = Severity::Error;
Expand Down Expand Up @@ -828,8 +835,12 @@ void DiagnosticSink::overrideDiagnosticSeverity(
{
SLANG_ASSERT(info->id == diagnosticId);

// If the override is the same as the default, we can just remove the override
if (info->severity == overrideSeverity)
// If the override is the same as the default, we can just remove the override -- but only
// for the always-on Default group. For a warning in an opt-in group (-Wall/-Wextra/
// -Wpedantic), an explicit override back to its nominal Warning severity is meaningful: it
// force-enables the warning even though its group is not enabled, so the override must be
// kept (an absent override would let group gating suppress it).
if (info->severity == overrideSeverity && info->level == WarningLevel::Default)
{
m_severityOverrides.remove(diagnosticId);
return;
Expand Down
77 changes: 77 additions & 0 deletions source/compiler-core/slang-diagnostic-sink.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,32 @@ enum class Severity
Internal
};

// The "level" (group) a warning belongs to, modeled on clang/gcc's -Wall/-Wextra/-Wpedantic
// groups. Groups are enabled independently (not nested): a warning is emitted only if its group
// is `Default` (always emitted) or its group has been explicitly enabled on the sink. Most
// diagnostics use `Default`; only warnings that should be opt-in are tagged with another group.
enum class WarningLevel
{
Default = 0,
All = 1,
Extra = 2,
Pedantic = 3,
};

// Keep the internal enum in sync with the public slang.h constants.
static_assert(
SLANG_WARNING_LEVEL_DEFAULT == int(WarningLevel::Default),
"mismatched WarningLevel enum values");
static_assert(
SLANG_WARNING_LEVEL_ALL == int(WarningLevel::All),
"mismatched WarningLevel enum values");
static_assert(
SLANG_WARNING_LEVEL_EXTRA == int(WarningLevel::Extra),
"mismatched WarningLevel enum values");
static_assert(
SLANG_WARNING_LEVEL_PEDANTIC == int(WarningLevel::Pedantic),
"mismatched WarningLevel enum values");

// Make sure that the slang.h severity constants match those defined here
static_assert(SLANG_SEVERITY_DISABLED == int(Severity::Disable), "mismatched Severity enum values");
static_assert(SLANG_SEVERITY_NOTE == int(Severity::Note), "mismatched Severity enum values");
Expand Down Expand Up @@ -60,6 +86,15 @@ struct DiagnosticInfo
Severity severity;
char const* name; ///< Unique name
char const* messageFormat;

/// The warning group this diagnostic belongs to. Only meaningful for warnings; the default of
/// `WarningLevel::Default` means "always emitted". Tagging a warning with another group gates
/// it on whether that group is currently enabled (see the enabled-groups bitmask below):
/// `Extra` is on by default, `All`/`Pedantic` are off by default, and each is toggled by the
/// corresponding -Wall/-Wextra/-Wpedantic flag (or the WarningLevel API option). Has a default
/// so the many aggregate initializers that predate this field (and the `DIAGNOSTIC(...)` macro
/// catalogs) keep compiling unchanged.
WarningLevel level = WarningLevel::Default;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
};

class Diagnostic
Expand Down Expand Up @@ -272,6 +307,36 @@ class DiagnosticSink
Severity overrideSeverity,
const DiagnosticInfo* info = nullptr);

/// Enable the given warning group (one of the -Wall/-Wextra/-Wpedantic groups). Warnings
/// tagged with that group will then be emitted. Enabling is additive; `WarningLevel::Default`
/// warnings are always emitted and need not be enabled.
///
/// The bit index is bounds-checked before shifting so that an out-of-range value (which can
/// only arrive from a bogus int cast through the public `CompilerOptionName::WarningLevel`
/// option) cannot produce an out-of-range shift, which is undefined behavior. Such values are
/// ignored here; `applySettingsToDiagnosticSink` also filters them at the API boundary.
void enableWarningLevel(WarningLevel level)
{
const auto bit = uint32_t(level);
if (bit < 32)
m_enabledWarningLevels |= (uint32_t(1) << bit);
}

/// Test whether a warning belonging to `level` should currently be emitted: true for the
/// always-on `Default` group, and for any group that has been enabled via enableWarningLevel.
bool isWarningLevelEnabled(WarningLevel level) const
{
if (level == WarningLevel::Default)
return true;
const auto bit = uint32_t(level);
return bit < 32 && (m_enabledWarningLevels & (uint32_t(1) << bit)) != 0;
}

/// Get/set the raw enabled-warning-group bitmask. Used to copy this settings-shaped state
/// between sinks (e.g. from a parent sink), mirroring getFlags/setFlags.
uint32_t getEnabledWarningLevels() const { return m_enabledWarningLevels; }
void setEnabledWarningLevels(uint32_t levels) { m_enabledWarningLevels = levels; }

/// Get the (optional) diagnostic sink lexer. This is used to
/// improve quality of highlighting a locations token. If not set, will just have a single
/// character caret at location
Expand Down Expand Up @@ -357,6 +422,7 @@ class DiagnosticSink
setFlags(parentSink->getFlags());
setDiagnosticColorMode(parentSink->getDiagnosticColorMode());
setEnableUnicode(parentSink->getEnableUnicode());
setEnabledWarningLevels(parentSink->getEnabledWarningLevels());
Comment thread
expipiplus1 marked this conversation as resolved.
Comment thread
expipiplus1 marked this conversation as resolved.
}
}
/// Default Ctor
Expand Down Expand Up @@ -423,6 +489,17 @@ class DiagnosticSink
// more precise per-diagnostic control.
Dictionary<int, Severity> m_severityOverrides;

// Bitmask of enabled warning groups, indexed by `WarningLevel`. The `Default` group is always
// on and is not represented here; other groups are opt-in (see enableWarningLevel).
//
// The groups are independent (not nested): a warning is gated on exactly the one group it is
// tagged with. By default the `Extra` group is on and the `Pedantic` group is off, so a
// `pedantic` warning is an advisory hint that fires only under `-Wpedantic`. A warning that
// should stay silent unless the user opts in belongs in `pedantic` (e.g.
// `vertex-shader-missing-sv-position`, which is a false positive whenever the vertex shader
// feeds a geometry/tessellation/mesh stage rather than the rasterizer).
uint32_t m_enabledWarningLevels = (uint32_t(1) << uint32_t(WarningLevel::Extra));

RefPtr<SourceWarningStateTrackerBase> m_sourceWarningStateTracker = nullptr;

// Rich diagnostics rendering options
Expand Down
19 changes: 19 additions & 0 deletions source/slang/slang-compiler-options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ bool CompilerOptionSet::allowDuplicate(CompilerOptionName name)
case CompilerOptionName::DisableWarning:
case CompilerOptionName::DisableWarnings:
case CompilerOptionName::EnableWarning:
case CompilerOptionName::WarningLevel:
case CompilerOptionName::Capability:
case CompilerOptionName::DownstreamArgs:
case CompilerOptionName::VulkanBindShift:
Expand Down Expand Up @@ -430,6 +431,24 @@ void applySettingsToDiagnosticSink(
Severity::Warning,
Severity::Error);
}
// Enable each requested warning group (-Wall/-Wextra/-Wpedantic). These are additive, so a
// diagnostic tagged with any enabled group becomes visible. `intValue` is embedder-controlled
// through the public WarningLevel option, so validate it here at the API boundary and ignore
// anything outside the known groups (Default is the always-on baseline and needs no enabling).
auto warningLevelArray = options.getArray(CompilerOptionName::WarningLevel);
for (auto& element : warningLevelArray)
{
switch (element.intValue)
{
case SLANG_WARNING_LEVEL_ALL:
case SLANG_WARNING_LEVEL_EXTRA:
case SLANG_WARNING_LEVEL_PEDANTIC:
targetSink->enableWarningLevel((WarningLevel)element.intValue);
break;
default:
break;
Comment thread
expipiplus1 marked this conversation as resolved.
Comment thread
expipiplus1 marked this conversation as resolved.
}
}
if (options.shouldEmitRichDiagnostics())
{
targetSink->setFlag(DiagnosticSink::Flag::AlwaysGenerateRichDiagnostics);
Expand Down
24 changes: 23 additions & 1 deletion source/slang/slang-diagnostics-helpers.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
-- Helper functions for defining diagnostics

-- Warning-level (group) sentinels. These are passed positionally to warning()/err() alongside
-- the spans (e.g. `warning("my-warning", 123, "msg", span{...}, pedantic)`), and recognised by
-- add_diagnostic so they don't get mistaken for a span. They mirror the clang/gcc groups: a
-- warning tagged with one of these is emitted only when the matching -Wall/-Wextra/-Wpedantic
-- flag is enabled. Untagged warnings stay in the always-on "default" group.
-- (There is no `default` sentinel because `default` is a Lua keyword and the absence of any
-- sentinel already means the default group.)
local warning_all = { is_warning_level = true, level = "all" }
local warning_extra = { is_warning_level = true, level = "extra" }
local warning_pedantic = { is_warning_level = true, level = "pedantic" }

-- Calculate Levenshtein edit distance between two strings
local function edit_distance(s1, s2)
local len1, len2 = #s1, #s2
Expand Down Expand Up @@ -378,6 +389,8 @@ local function add_diagnostic(name, code, severity, message, primary_span, ...)
severity = severity,
message = message,
primary_span = primary_span,
-- Warning group; "default" (always emitted) unless a sentinel below overrides it.
level = "default",
}

local extra_spans = { ... }
Expand All @@ -386,7 +399,11 @@ local function add_diagnostic(name, code, severity, message, primary_span, ...)
local notes = {}

for _, s in ipairs(extra_spans) do
if s.is_note then
if s.is_warning_level then
-- A warning-level sentinel (all/extra/pedantic): record the group and skip it; it is
-- not a span or note.
diag.level = s.level
elseif s.is_note then
Comment thread
expipiplus1 marked this conversation as resolved.
table.insert(notes, {
location = s.location,
message = s.message,
Expand Down Expand Up @@ -1055,6 +1072,7 @@ local function process_diagnostics(diagnostics_table)
name = diag.name,
code = diag.code,
severity = diag.severity,
level = diag.level or "default",
message = diag.message,
message_parts = main_parts,
message_required_params = main_required,
Expand Down Expand Up @@ -1110,6 +1128,10 @@ return {
warning = warning,
internal = internal,
fatal = fatal,
-- Warning-level (group) sentinels passed positionally to warning()/err().
all = warning_all,
extra = warning_extra,
pedantic = warning_pedantic,
process_diagnostics = process_diagnostics,
-- Utility functions for typo suggestions
edit_distance = edit_distance,
Expand Down
21 changes: 19 additions & 2 deletions source/slang/slang-diagnostics.lua
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ local err = helpers.err
local warning = helpers.warning
local internal = helpers.internal
local fatal = helpers.fatal
-- Warning-level (group) sentinel: pass one positionally to warning() to make that warning
-- opt-in behind a -W group flag, e.g.
-- warning("my-warning", 123, "message", span{...}, pedantic)
-- `extra` is on by default and `pedantic` is off by default (see DiagnosticSink); `helpers.all`
-- exists for the third group and can be bound here when a diagnostic needs it.
local extra = helpers.extra
local pedantic = helpers.pedantic

--
-- 0xxxx - Command line and interaction with host platform APIs.
Expand Down Expand Up @@ -939,7 +946,12 @@ warning(
"keyword-used-as-name",
20103,
"keyword used as a name",
span { loc = "location", message = "'~name:Name' is a type keyword; using it as a name may make the name ambiguous or impossible to reference in some contexts" }
span { loc = "location", message = "'~name:Name' is a type keyword; using it as a name may make the name ambiguous or impossible to reference in some contexts" },
-- Extra: using a type keyword as a name is legal and usually works, so this is a
-- style/portability hint rather than a likely bug. It lives in the `extra` group (on by
-- default) rather than `pedantic` because the diagnostic still points at a real, if benign,
-- footgun in the user's own code.
extra
)

err(
Expand Down Expand Up @@ -4428,7 +4440,12 @@ warning(
"vertex-shader-missing-sv-position",
38052,
"vertex shader '~entryPoint:Name' has no output with the 'SV_Position' system value semantic",
span { loc = "location", message = "vertex shader '~entryPoint:Name' has no output with the 'SV_Position' system value semantic; the rasterizer will not receive valid vertex positions (add 'SV_Position' to a vertex output, or suppress with -warnings-disable 38052)" }
span { loc = "location", message = "vertex shader '~entryPoint:Name' has no output with the 'SV_Position' system value semantic; if it feeds the rasterizer directly, the rasterizer will not receive valid vertex positions (add 'SV_Position' to a vertex output)" },
-- Pedantic (off by default): a vertex shader may legitimately omit SV_Position when its output
-- feeds a geometry/tessellation/mesh stage that supplies the position itself (see #11884), and
-- at VS-compile time we cannot tell that case apart from a real missing-position bug. The check
-- is a false positive too often to run by default, so it is opt-in via -Wpedantic.
pedantic
Comment thread
expipiplus1 marked this conversation as resolved.
)

--
Expand Down
26 changes: 26 additions & 0 deletions source/slang/slang-options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,10 @@ void initCommandOptions(CommandOptions& options)
"-warnings-disable",
"-warnings-disable <id>[,<id>...]",
"Disable specific warning ids."},
{OptionKind::WarningLevel,
"-Wall,-Wextra,-Wpedantic",
"-Wall | -Wextra | -Wpedantic",
"Enable the corresponding group of opt-in warnings (additive)."},
{OptionKind::EnableWarning, "-W...", "-W<id>", "Enable a warning with the specified id."},
{OptionKind::DisableWarning, "-Wno-...", "-Wno-<id>", "Disable warning with <id>"},
{OptionKind::DumpWarningDiagnostics,
Expand Down Expand Up @@ -3050,6 +3054,28 @@ SlangResult OptionsParser::_parse(int argc, char const* const* argv)
// Severity::Warning));
break;
}
case OptionKind::WarningLevel:
{
// The flag spelling (-Wall/-Wextra/-Wpedantic) selects which warning group to
// enable. Exact-match options take priority over the -W<id> prefix, so these are
// never confused with `-W<name>`.
auto flag = argValue.getUnownedSlice();
SlangWarningLevel level;
if (flag == "-Wall")
level = SLANG_WARNING_LEVEL_ALL;
else if (flag == "-Wextra")
level = SLANG_WARNING_LEVEL_EXTRA;
else if (flag == "-Wpedantic")
level = SLANG_WARNING_LEVEL_PEDANTIC;
else
{
// Only the three exact flags above are registered for WarningLevel, so any
// other spelling reaching here is a wiring bug, not user input.
SLANG_UNEXPECTED("unhandled -W warning-level flag");
}
linkage->m_optionSet.add(OptionKind::WarningLevel, (int)level);
break;
}
case OptionKind::VerifyDebugSerialIr:
m_frontEndReq->verifyDebugSerialization = true;
break;
Expand Down
Loading
Loading