Fix #11473: pragma warning state corruption across __include passes#11478
Fix #11473: pragma warning state corruption across __include passes#11478nv-slang-bot[bot] wants to merge 1 commit into
Conversation
…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
|
Suggested reviewers (no ping; based on
|
|
FYI: filed #11479 to track the |
|
CI ran and reported two non-aggregator failures: Both surfaces are disjoint from this PR's diff — adding a Same checks pass on contemporary peer PRs (#11431, #11430, #11420). Re-running the failed jobs to disambiguate flake from a master regression that landed between those green peers and now. |
CI rerun classification
These are language-server / workspace symbols, all defined in Confirmed via build log: both Provenance check:
Hypothesis: latent breakage in master at Asks:
|
Fixes #11473.
Motivation
#pragma warning(disable: <id>)at the root translation-unit level can be silently clobbered by an unrelated#pragma warning(push)/(pop)inside an__included module file. Reduced repro from the issue:-Wno-30856on the command line works (separate suppression path); only the in-source root pragma is broken.Root cause (two combined facets)
__includeis a Slang declaration parsed inslang-parser.cpp.SemanticsDeclHeaderVisitor::visitIncludeDeclcallsLinkage::findAndIncludeFile, which runs a freshpreprocessSourcepass per included file. Each fresh pass constructs a newPreprocessorwhoseabsoluteSourceLocCounterdefaults to 0, andPreprocessor::pushInputFilecallssourceView->setAbsoluteLocationBase(absoluteSourceLocCounter). Net effect: every__included file's absolute-loc range starts at 0.Cross-file pragma state is shared via a sink-attached
WarningStateTracker. ItsWarningTimelineis keyed by absoluteSourceLoc::RawValue, andaddPragmaPopblanket-restores every known diagnostic id by looking upfindEntry(absPushed)for each id, then writing the resulting specifier at the pop's absolute loc. With colliding 0-bases across passes, the timeline lookup misses the root-TU disable and the pop reverts 30856 toDefault. Subsequent emissions of 30856 then fire.A push/pop placed inline in a single preprocessing pass works correctly — the absolute axis is monotonic there — which isolates facet 1 as the trigger.
Fix shape
Carry the high-water mark of
absoluteSourceLocCounteracrosspreprocessSourcepasses via the already-sharedWarningStateTracker(the only object that already lives per-TU across the N passes spawned by__include). At the start of each pass, seed the new preprocessor's counter from the tracker; at the end, write the new high-water mark back. Every later pass's locations now land strictly after the prior pass's max, so the per-id timeline binary search continues to find the correct push-time entry and the root-level disable survives across__includeboundaries.The internal timeline logic (
WarningTimeline::findEntryisstd::upper_boundon a sorted list) is already correct under monotonic locations — the only change needed is the cross-pass seeding.Footprint: one new field on
WarningStateTrackerplus one seed and one write-back inpreprocessSource.Test
tests/diagnostics/pragma-warning-include-empty-pop-{main,body,footer}.slangreproduces the original three-file pattern (root disable + body produces 30856 + footer's unrelated push/pop).// CHECK-NOT: warning 30856fires on master and passes after the fix.Also verified locally with
slangc -no-codegenthat the existingtests/diagnostics/nested-pragma-*.slangfamily continues to suppress 30856 as before. Existingtests/diagnostics/pragma-warning-multifile-*.slangwas already a known-failing regression test (its impl2 contains the comment "This should still NOT produce warning 30856 (but currently does due to the bug)"); behaviour there is unchanged by this PR — its expectation that apopinside one included file should not extend the disable into a sibling included file is a separate, narrower question and out of scope here.Out of scope (possible follow-up)
Triage suggested also scoping
addPragmaPopto restore only the ids modified between the matchingpush/poprather than blanket-restoring all known ids. That is an independent robustness improvement — useful, but it changes the data structure and the semantics ofpopin subtle ways, so I left it out of this minimal fix. Filing as a follow-up makes sense if reviewers agree.Notes
source/slang/slang-preprocessor.cpp; the new field is on aRefObjectsubclass that is never crossed over a public boundary).pr: non-breaking.