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