From 5871128ed85626f2475aea4b725e955f455a4d1a Mon Sep 17 00:00:00 2001 From: "nv-slang-bot[bot]" <274397474+nv-slang-bot[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 19:12:42 +0000 Subject: [PATCH] slang-preprocessor: keep absoluteSourceLocCounter monotonic across __include passes Each `__include`d file is preprocessed in a fresh `preprocessSource` pass that constructs a new Preprocessor with absoluteSourceLocCounter defaulting to 0. The shared sink-attached WarningStateTracker keys its per-id timelines by absolute SourceLoc, so colliding 0-bases from different files break the timeline ordering: a `#pragma warning(pop)` in a later __include'd file blanket-restores every known id by looking up findEntry(pushedLocation), which under collisions misses the root-TU disable and reverts the id to Default. The user's root-level `#pragma warning(disable: 30856)` then no longer applies on subsequent emissions. Carry the high-water mark of absoluteSourceLocCounter across passes via the already-shared WarningStateTracker. Every later pass's locations land strictly after the prior pass's max, so the timeline binary search finds the correct push-time entry and the root disable survives. The internal timeline logic is unchanged. Fixes #11473 --- source/slang/slang-preprocessor.cpp | 33 +++++++++++++++++++ ...ragma-warning-include-empty-pop-body.slang | 9 +++++ ...gma-warning-include-empty-pop-footer.slang | 5 +++ ...ragma-warning-include-empty-pop-main.slang | 10 ++++++ 4 files changed, 57 insertions(+) create mode 100644 tests/diagnostics/pragma-warning-include-empty-pop-body.slang create mode 100644 tests/diagnostics/pragma-warning-include-empty-pop-footer.slang create mode 100644 tests/diagnostics/pragma-warning-include-empty-pop-main.slang diff --git a/source/slang/slang-preprocessor.cpp b/source/slang/slang-preprocessor.cpp index 6e79511b719..3129fd403aa 100644 --- a/source/slang/slang-preprocessor.cpp +++ b/source/slang/slang-preprocessor.cpp @@ -1191,6 +1191,16 @@ struct WarningStateTracker : SourceWarningStateTrackerBase Dictionary mapDiagnosticIdToTimeline = {}; List stack = {}; + // High-water mark of `Preprocessor::absoluteSourceLocCounter`, carried + // across the multiple `preprocessSource` passes that share this tracker + // within a single translation unit (one pass for the root file plus one + // per `__include`d module file). Each pass seeds its preprocessor counter + // from this value at start and writes the new high-water mark back at + // end, so absolute locations across passes stay strictly monotonic and + // the per-id timeline binary search continues to find the correct push + // entry for a `#pragma warning(pop)`. + SourceLoc::RawValue absoluteLocCounter = 0; + WarningStateTracker(SourceManager* sourceManager = nullptr) : sourceManager(sourceManager) { @@ -5028,6 +5038,19 @@ TokenList preprocessSource( preprocessor.warningStateTracker = dynamicCast(desc.sink->getSourceWarningStateTracker()); + // Seed the absolute-loc counter from the shared per-TU tracker so that + // locations produced by this pass are strictly larger than any location + // produced by earlier passes (root file + previously processed + // `__include`d files). Without this, every pass starts at 0 and the + // pragma warning timelines (keyed by absolute loc) collide across files, + // which can cause `#pragma warning(pop)` in one included file to + // silently revert a `#pragma warning(disable: )` in another file. + if (preprocessor.warningStateTracker) + { + preprocessor.absoluteSourceLocCounter = + preprocessor.warningStateTracker->absoluteLocCounter; + } + // Add builtin macros { auto namePool = desc.namePool; @@ -5111,6 +5134,16 @@ TokenList preprocessSource( outDetectedLanguage = preprocessor.language; if (preprocessor.languageVersion != SLANG_LANGUAGE_VERSION_UNKNOWN) outLanguageVersion = preprocessor.languageVersion; + + // Carry the high-water mark forward so the next `preprocessSource` pass + // for this translation unit (e.g. an `__include`d module file) starts + // its absolute locations strictly after ours. + if (preprocessor.warningStateTracker) + { + preprocessor.warningStateTracker->absoluteLocCounter = + preprocessor.absoluteSourceLocCounter; + } + return tokens; } diff --git a/tests/diagnostics/pragma-warning-include-empty-pop-body.slang b/tests/diagnostics/pragma-warning-include-empty-pop-body.slang new file mode 100644 index 00000000000..1e22395e402 --- /dev/null +++ b/tests/diagnostics/pragma-warning-include-empty-pop-body.slang @@ -0,0 +1,9 @@ +implementing pragma_warning_include_empty_pop; + +namespace body_ns +{ + interface IConvertibleFrom {} + + extension, let N : int> + vector : IConvertibleFrom> {} +} diff --git a/tests/diagnostics/pragma-warning-include-empty-pop-footer.slang b/tests/diagnostics/pragma-warning-include-empty-pop-footer.slang new file mode 100644 index 00000000000..d155173283b --- /dev/null +++ b/tests/diagnostics/pragma-warning-include-empty-pop-footer.slang @@ -0,0 +1,5 @@ +implementing pragma_warning_include_empty_pop; + +#pragma warning(push) +#pragma warning(disable: 31000) +#pragma warning(pop) diff --git a/tests/diagnostics/pragma-warning-include-empty-pop-main.slang b/tests/diagnostics/pragma-warning-include-empty-pop-main.slang new file mode 100644 index 00000000000..801fd89257d --- /dev/null +++ b/tests/diagnostics/pragma-warning-include-empty-pop-main.slang @@ -0,0 +1,10 @@ +//TEST:SIMPLE(filecheck=CHECK): + +module pragma_warning_include_empty_pop; + +#pragma warning(disable: 30856) + +__include "pragma-warning-include-empty-pop-body.slang"; +__include "pragma-warning-include-empty-pop-footer.slang"; + +// CHECK-NOT: warning 30856