C++: Handle field initialization via NSDMI in IR generation#21391
Open
jketema wants to merge 16 commits intogithub:mainfrom
Open
C++: Handle field initialization via NSDMI in IR generation#21391jketema wants to merge 16 commits intogithub:mainfrom
jketema wants to merge 16 commits intogithub:mainfrom
Conversation
671d8f6 to
0a26534
Compare
bc2663d to
ce86619
Compare
cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll
Fixed
Show fixed
Hide fixed
cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll
Fixed
Show fixed
Hide fixed
823eaab to
61b75e3
Compare
Currently missing: side-effect information for the functions
These need to be looked at, but because data flow through default field initialization is currently not working, let's postpone this as part of that work.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends the C++ IR generation pipeline to represent non-static data member initializers (NSDMI) by generating synthetic IR “functions” for field initializers, and updates the AST/IR APIs and tests accordingly.
Changes:
- Introduces
ConstructorDirectFieldInitandConstructorDefaultFieldInitto distinguish explicit ctor member-initializer-list initializers from default member initializers. - Adds IR translation support for field initializers via a new translated element (
TranslatedNonStaticDataMemberVarInit) and associated side-effect plumbing. - Updates IR
FunctionAddress/Callsymbol handling fromFunctiontoDeclaration, and refreshes test baselines/expectations.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| cpp/ql/test/library-tests/ir/ir/raw_ir.expected | Updates raw IR expectations to include synthetic field-init calls/functions. |
| cpp/ql/test/library-tests/ir/ir/raw_consistency.expected | Updates raw IR consistency expectations (removes one prior issue). |
| cpp/ql/test/library-tests/ir/ir/ir.cpp | Adds StructInit test coverage for NSDMI patterns. |
| cpp/ql/test/library-tests/ir/ir/aliased_ir.expected | Updates aliased IR expectations to include synthetic field-init calls/functions. |
| cpp/ql/test/library-tests/ir/ir/PrintConfig.qll | Adjusts IR dumping config to include fields with initializers. |
| cpp/ql/test/library-tests/ir/ir/PrintAST.expected | Updates AST expectations to new ctor-init node kinds and includes StructInit. |
| cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.expected | Updates expected IR type-bug outputs (now includes new entries). |
| cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp | Adds NSDMI-focused dataflow test cases. |
| cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected | Adds expected source→sink flow for the explicit ctor-init NSDMI case. |
| cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected | Updates expected dataflow consistency violations (now includes NSDMI initializer call). |
| cpp/ql/test/library-tests/ctorinits/ctors.expected | Updates ctor-init classification expectations to ConstructorDirectFieldInit. |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll | Broadens static call target symbol typing from Function to Declaration. |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedNonStaticDataMember.qll | Adds translation root for non-static data member variable initialization (new). |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll | Extends initialization translation to cover fields and default-field-init calls. |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll | Routes expression translation through field-init synthetic roots where applicable. |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll | Adds new translated element variants for default field init and field-init roots. |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll | Excludes fields from statement-enclosing callable inference in declaration entries. |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll | Extends condition translation “enclosing declaration” support to fields. |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll | Extends call side-effect handling to cover default field initializations. |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll | Generalizes “call side effects” expression handling to include default field init. |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll | Treats fields with initializers as IR-function-backed declarations and variables. |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll | Broadens function-address symbol typing from Function to Declaration. |
| cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll | Broadens function-address symbol typing from Function to Declaration. |
| cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll | Adds explicit casts where static call targets are now Declaration. |
| cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll | Adds explicit casts where static call targets are now Declaration. |
| cpp/ql/lib/semmle/code/cpp/exprs/Call.qll | Adds/defines new ctor field-init AST node classes and documentation. |
| cpp/ql/lib/change-notes/2026-03-24-field-init.md | Documents the new ctor-init AST node classes as a feature. |
cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
Show resolved
Hide resolved
cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll
Outdated
Show resolved
Hide resolved
cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
Show resolved
Hide resolved
cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected
Show resolved
Hide resolved
cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll
Outdated
Show resolved
Hide resolved
cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll
Show resolved
Hide resolved
…slatedCall.qll Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Handle NSDMI in IR generation. Commit-by-commit review is recommended.
There are effectively two options here:
a. Generate a function for each default initialization that does the initialization
b. Duplicate the default initialization in each constructor that uses it
The former works better with the invariant we have in the IR that each AST node maps to at most one IR node. Hence, is the approach taken here.
For the generated functions there are again several options:
thispointer to the functionthispointer, as other fields may need to be accessed during initialization)thispointer).Option (1) is the option taken here. I did not explore (2), as it seemed a more complicated version of (1), where a little bit of code could have been shared with direct field initialization (getting the field address). Option (3) would have allowed for more sharing with direct field initialization. I explored (3) for a bit, but that ended me up in rabbit hole where I needed to modify much more IR generation, because some of the expression translations expect that they have direct access to a field address (which was no longer passed to the initialization function).
The disadvantage of (1) compared to (3) is that data flow does not work out-of-the box. However, this should be straightforward to fix.