Skip to content

Reset sticky diagnostic state after a rejected InstantiateTemplate#1070

Open
conrade-ctc wants to merge 1 commit into
compiler-research:mainfrom
conrade-ctc:reset-diags-after-rejected-instantiation
Open

Reset sticky diagnostic state after a rejected InstantiateTemplate#1070
conrade-ctc wants to merge 1 commit into
compiler-research:mainfrom
conrade-ctc:reset-diags-after-rejected-instantiation

Conversation

@conrade-ctc

@conrade-ctc conrade-ctc commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Description

A rejected Cpp::InstantiateTemplate (e.g. a type argument supplied for a non-type template parameter) emits its error diagnostic outside any incremental parse, and DiagnosticsEngine's ErrorOccurred flag is sticky. The next IncrementalParser::Parse sees the stale flag after a perfectly good parse, reports "Parsing failed.", and soft-resets the engine — so exactly one subsequent Cpp::Declare/Process fails spuriously. Downstream (cppyy), one rejected template subscript makes the next cppyy.include/cppyy.cppdef report failure while actually loading the code, which can silently corrupt fail-soft feature probes.

Per review, the rejection is now contained by a DiagnosticErrorTrap-based RAII (StickyDiagnosticResetRAII): the trap detects errors introduced during the instantiation, and on scope exit the guard restores a clean state with the same Diags.Reset(/*soft=*/true) + client clear() cleanup that IncrementalParser performs on a real parse failure (and that InstantiateFunctionDefinition performs inline). The rejection's diagnostic text is still emitted to the client as before.

Type of change

  • Bug fix

Testing

New ScopeReflection_RejectedInstantiationDoesNotPoisonNextParse: a rejected instantiation followed by two Cpp::Declare calls, both of which must succeed. Fails before the fix (the first Declare reports failure), passes after.

Checklist

  • I have read the contribution guide recently

🤖 Done with the help of Claude Code (Fable 5, human in the loop)

Comment thread lib/CppInterOp/CppInterOp.cpp Outdated
// the incremental parser performs on a real parse failure).
clang::DiagnosticsEngine& Diags = S.getDiagnostics();
bool HadErrors = Diags.hasErrorOccurred();
Decl* Result = InstantiateTemplate(TmplD, TemplateArgs, S, instantiate_body);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can can insert a diagnostic trap object -- we have that elsewhere in the codebase.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

indeed, thanks for pointing that out, update forth-coming!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done — the manual snapshot is now a DiagnosticErrorTrap-based RAII (StickyDiagnosticResetRAII): the trap detects errors introduced during the instantiation, and on scope exit the guard restores a clean state with the same Diags.Reset(/*soft=*/true) + client clear() cleanup IncrementalParser performs on a real parse failure. I left InstantiateFunctionDefinition's inline copy of this cleanup untouched — it could migrate to the same guard, but #849 is already touching that spot and I didn't want the two PRs to collide.

@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.04%. Comparing base (3103be9) to head (4fd6208).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1070      +/-   ##
==========================================
+ Coverage   87.01%   87.04%   +0.03%     
==========================================
  Files          23       23              
  Lines        6069     6076       +7     
==========================================
+ Hits         5281     5289       +8     
+ Misses        788      787       -1     
Files with missing lines Coverage Δ
lib/CppInterOp/CppInterOp.cpp 89.56% <100.00%> (+0.05%) ⬆️
Files with missing lines Coverage Δ
lib/CppInterOp/CppInterOp.cpp 89.56% <100.00%> (+0.05%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@conrade-ctc
conrade-ctc force-pushed the reset-diags-after-rejected-instantiation branch from 803d04c to b6fee6d Compare July 16, 2026 17:51
The rejection (e.g. a type argument for a non-type parameter) emits its
error diagnostic outside any incremental parse, and DiagnosticsEngine's
ErrorOccurred flag is sticky: the next IncrementalParser::Parse reported
the stale flag as its own failure and then soft-reset it, poisoning
exactly one parse. Contain the rejection with a DiagnosticErrorTrap-based
RAII that restores a clean diagnostic state when the instantiation
introduced errors - the same cleanup IncrementalParser performs on a real
parse failure and InstantiateFunctionDefinition performs inline.

Co-developed-with-the-help-of: Claude Code (Fable 5, human in the loop)
@conrade-ctc
conrade-ctc force-pushed the reset-diags-after-rejected-instantiation branch from b6fee6d to 4fd6208 Compare July 16, 2026 17:51
@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants