diff --git a/.bazelrc b/.bazelrc
index 12232b4bbd68..c2b4d3b7f03e 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -14,4 +14,11 @@ build:linux --cxxopt=-std=c++20
build:macos --cxxopt=-std=c++20 --cpu=darwin_x86_64
build:windows --cxxopt=/std:c++20 --cxxopt=/Zc:preprocessor
+# this requires developer mode, but is required to have pack installer functioning
+startup --windows_enable_symlinks
+common --enable_runfiles
+
+common --registry=file:///%workspace%/misc/bazel/registry
+common --registry=https://bcr.bazel.build
+
try-import %workspace%/local.bazelrc
diff --git a/.bazelrc.internal b/.bazelrc.internal
new file mode 100644
index 000000000000..cdffa9ccdea6
--- /dev/null
+++ b/.bazelrc.internal
@@ -0,0 +1,4 @@
+# this file should contain bazel settings required to build things from `semmle-code`
+
+common --registry=file:///%workspace%/ql/misc/bazel/registry
+common --registry=https://bcr.bazel.build
diff --git a/.github/workflows/buildifier.yml b/.github/workflows/buildifier.yml
new file mode 100644
index 000000000000..b5d1e2244d5c
--- /dev/null
+++ b/.github/workflows/buildifier.yml
@@ -0,0 +1,28 @@
+name: Check bazel formatting
+
+on:
+ pull_request:
+ paths:
+ - "**.bazel"
+ - "**.bzl"
+ branches:
+ - main
+ - "rc/*"
+
+permissions:
+ contents: read
+
+jobs:
+ check:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Check bazel formatting
+ uses: pre-commit/action@646c83fcd040023954eafda54b4db0192ce70507
+ with:
+ extra_args: >
+ buildifier --all-files 2>&1 ||
+ (
+ echo -e "In order to format all bazel files, please run:\n bazel run //misc/bazel:buildifier"; exit 1
+ )
diff --git a/.lfsconfig b/.lfsconfig
new file mode 100644
index 000000000000..cb0a8e352e86
--- /dev/null
+++ b/.lfsconfig
@@ -0,0 +1,5 @@
+[lfs]
+# codeql is publicly forked by many users, and we don't want any LFS file polluting their working
+# copies. We therefore exclude everything by default.
+# For files required by bazel builds, use rules in `misc/bazel/lfs.bzl` to download them on demand.
+fetchinclude = /nothing
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 383bc1103837..051044904686 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -20,13 +20,22 @@ repos:
- id: autopep8
files: ^misc/codegen/.*\.py
- - repo: https://github.com/warchant/pre-commit-buildifier
- rev: 0.0.2
+ - repo: local
hooks:
- id: buildifier
+ name: Format bazel files
+ files: \.(bazel|bzl)
+ language: system
+ entry: bazel run //misc/bazel:buildifier
+ pass_filenames: false
+
+ - id: go-gen
+ name: Check checked in generated files in go
+ files: ^go/.*
+ language: system
+ entry: bazel run //go:gen
+ pass_filenames: false
- - repo: local
- hooks:
- id: codeql-format
name: Fix QL file formatting
files: \.qll?$
diff --git a/MODULE.bazel b/MODULE.bazel
index 4e1fe0d9f7cb..27479e1978f7 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -13,7 +13,8 @@ local_path_override(
# see https://registry.bazel.build/ for a list of available packages
-bazel_dep(name = "platforms", version = "0.0.8")
+bazel_dep(name = "platforms", version = "0.0.9")
+bazel_dep(name = "rules_go", version = "0.47.0")
bazel_dep(name = "rules_pkg", version = "0.10.1")
bazel_dep(name = "rules_nodejs", version = "6.0.3")
bazel_dep(name = "rules_python", version = "0.31.0")
@@ -21,6 +22,9 @@ bazel_dep(name = "bazel_skylib", version = "1.5.0")
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
bazel_dep(name = "fmt", version = "10.0.0")
+bazel_dep(name = "gazelle", version = "0.36.0")
+
+bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
@@ -50,6 +54,9 @@ node.toolchain(
)
use_repo(node, "nodejs", "nodejs_toolchains")
+go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
+go_sdk.download(version = "1.22.2")
+
register_toolchains(
"@nodejs_toolchains//:all",
)
diff --git a/config/identical-files.json b/config/identical-files.json
index a8b1368f1af4..d810e30c0c8e 100644
--- a/config/identical-files.json
+++ b/config/identical-files.json
@@ -362,7 +362,7 @@
"java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll"
],
"Python model summaries test extension": [
- "python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ext.yml",
- "python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml"
+ "python/ql/test/library-tests/dataflow/model-summaries/InlineTaintTest.ext.yml",
+ "python/ql/test/library-tests/dataflow/model-summaries/NormalDataflowTest.ext.yml"
]
-}
\ No newline at end of file
+}
diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md
index e480b46a279d..bcb7d30a2ed9 100644
--- a/cpp/ql/lib/CHANGELOG.md
+++ b/cpp/ql/lib/CHANGELOG.md
@@ -1,3 +1,20 @@
+## 0.13.0
+
+### Breaking Changes
+
+* Deleted the deprecated `GlobalValueNumberingImpl.qll` implementation.
+
+### New Features
+
+* Models-as-Data support has been added for C/C++. This feature allows flow sources, sinks and summaries to be expressed in compact strings as an alternative to modelling each source / sink / summary with explicit QL. See `dataflow/ExternalFlow.qll` for documentation and specification of the model format, and `models/implementations/ZMQ.qll` for a simple example of models. Importing models from `.yml` is not yet supported.
+
+### Minor Analysis Improvements
+
+* Source models have been added for the standard library function `getc` (and variations).
+* Source, sink and flow models for the ZeroMQ (ZMQ) networking library have been added.
+* Parameters of functions without definitions now have `ParameterNode`s.
+* The alias analysis used internally by various libraries has been improved to answer alias questions more conservatively. As a result, some queries may report fewer false positives.
+
## 0.12.11
No user-facing changes.
diff --git a/cpp/ql/lib/change-notes/2024-04-05-sound-ir.md b/cpp/ql/lib/change-notes/2024-04-05-sound-ir.md
deleted file mode 100644
index 0bb930934168..000000000000
--- a/cpp/ql/lib/change-notes/2024-04-05-sound-ir.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* The alias analysis used internally by various libraries has been improved to answer alias questions more conservatively. As a result, some queries may report fewer false positives.
\ No newline at end of file
diff --git a/cpp/ql/lib/change-notes/2024-04-18-param-nodes.md b/cpp/ql/lib/change-notes/2024-04-18-param-nodes.md
deleted file mode 100644
index 1911af38d8a0..000000000000
--- a/cpp/ql/lib/change-notes/2024-04-18-param-nodes.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Parameters of functions without definitions now have `ParameterNode`s.
diff --git a/cpp/ql/lib/change-notes/2024-10-04-getc.md b/cpp/ql/lib/change-notes/2024-10-04-getc.md
deleted file mode 100644
index 9174b7a11848..000000000000
--- a/cpp/ql/lib/change-notes/2024-10-04-getc.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Source models have been added for the standard library function `getc` (and variations).
diff --git a/cpp/ql/lib/change-notes/2024-10-04-models-as-data.md b/cpp/ql/lib/change-notes/2024-10-04-models-as-data.md
deleted file mode 100644
index 83e660cdb649..000000000000
--- a/cpp/ql/lib/change-notes/2024-10-04-models-as-data.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: feature
----
-* Models-as-Data support has been added for C/C++. This feature allows flow sources, sinks and summaries to be expressed in compact strings as an alternative to modelling each source / sink / summary with explicit QL. See `dataflow/ExternalFlow.qll` for documentation and specification of the model format, and `models/implementations/ZMQ.qll` for a simple example of models. Importing models from `.yml` is not yet supported.
diff --git a/cpp/ql/lib/change-notes/2024-10-04-zmq.md b/cpp/ql/lib/change-notes/2024-10-04-zmq.md
deleted file mode 100644
index 2800a4d55b34..000000000000
--- a/cpp/ql/lib/change-notes/2024-10-04-zmq.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Source, sink and flow models for the ZeroMQ (ZMQ) networking library have been added.
diff --git a/cpp/ql/lib/change-notes/released/0.13.0.md b/cpp/ql/lib/change-notes/released/0.13.0.md
new file mode 100644
index 000000000000..84dc06b699cb
--- /dev/null
+++ b/cpp/ql/lib/change-notes/released/0.13.0.md
@@ -0,0 +1,16 @@
+## 0.13.0
+
+### Breaking Changes
+
+* Deleted the deprecated `GlobalValueNumberingImpl.qll` implementation.
+
+### New Features
+
+* Models-as-Data support has been added for C/C++. This feature allows flow sources, sinks and summaries to be expressed in compact strings as an alternative to modelling each source / sink / summary with explicit QL. See `dataflow/ExternalFlow.qll` for documentation and specification of the model format, and `models/implementations/ZMQ.qll` for a simple example of models. Importing models from `.yml` is not yet supported.
+
+### Minor Analysis Improvements
+
+* Source models have been added for the standard library function `getc` (and variations).
+* Source, sink and flow models for the ZeroMQ (ZMQ) networking library have been added.
+* Parameters of functions without definitions now have `ParameterNode`s.
+* The alias analysis used internally by various libraries has been improved to answer alias questions more conservatively. As a result, some queries may report fewer false positives.
diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml
index 18a7ef452ef3..5a1b274ee587 100644
--- a/cpp/ql/lib/codeql-pack.release.yml
+++ b/cpp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.12.11
+lastReleaseVersion: 0.13.0
diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml
index 4691c2b2a9af..b87cf42fb6fb 100644
--- a/cpp/ql/lib/qlpack.yml
+++ b/cpp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-all
-version: 0.12.12-dev
+version: 0.13.1-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
diff --git a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll
index beabef322d20..b515a346bf3b 100644
--- a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll
+++ b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll
@@ -463,6 +463,25 @@ class StmtNode extends AstNode {
}
}
+/**
+ * A node representing a child of a `Stmt` that is itself a `Stmt`.
+ */
+class ChildStmtNode extends StmtNode {
+ Stmt childStmt;
+
+ ChildStmtNode() { exists(Stmt parent | parent.getAChild() = childStmt and childStmt = ast) }
+
+ override BaseAstNode getChildInternal(int childIndex) {
+ result = super.getChildInternal(childIndex)
+ or
+ exists(int destructorIndex |
+ result.getAst() = childStmt.getImplicitDestructorCall(destructorIndex) and
+ childIndex =
+ destructorIndex + max(int index | exists(childStmt.getChild(index)) or index = 0) + 1
+ )
+ }
+}
+
/**
* A node representing a `DeclStmt`.
*/
@@ -674,6 +693,13 @@ class FunctionNode extends FunctionOrGlobalOrNamespaceVariableNode {
private string getChildAccessorWithoutConversions(Locatable parent, Element child) {
shouldPrintDeclaration(getAnEnclosingDeclaration(parent)) and
(
+ exists(Stmt s, int i | s.getChild(i) = parent |
+ exists(int n |
+ s.getChild(i).(Stmt).getImplicitDestructorCall(n) = child and
+ result = "getImplicitDestructorCall(" + n + ")"
+ )
+ )
+ or
exists(Stmt s | s = parent |
namedStmtChildPredicates(s, child, result)
or
diff --git a/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll
index ee419dd70249..83f8dc8b3bc7 100644
--- a/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll
+++ b/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll
@@ -790,6 +790,27 @@ private predicate simple_comparison_eq(Instruction test, Operand op, int k, Abst
exists(switch.getSuccessor(case)) and
case.getValue().toInt() = k
)
+ or
+ // There's no implicit CompareInstruction in files compiled as C since C
+ // doesn't have implicit boolean conversions. So instead we check whether
+ // there's a branch on a value of pointer or integer type.
+ exists(ConditionalBranchInstruction branch, IRType type |
+ not test instanceof CompareInstruction and
+ type = test.getResultIRType() and
+ (type instanceof IRAddressType or type instanceof IRIntegerType) and
+ test = branch.getCondition() and
+ op.getDef() = test
+ |
+ // We'd like to also include a case such as:
+ // ```
+ // k = 1 and
+ // value.(BooleanValue).getValue() = true
+ // ```
+ // but all we know is that the value is non-zero in the true branch.
+ // So we can only conclude something in the false branch.
+ k = 0 and
+ value.(BooleanValue).getValue() = false
+ )
}
private predicate complex_eq(
@@ -1156,5 +1177,14 @@ private predicate add_eq(
)
}
+private class IntegerOrPointerConstantInstruction extends ConstantInstruction {
+ IntegerOrPointerConstantInstruction() {
+ this instanceof IntegerConstantInstruction or
+ this instanceof PointerConstantInstruction
+ }
+}
+
/** The int value of integer constant expression. */
-private int int_value(Instruction i) { result = i.(IntegerConstantInstruction).getValue().toInt() }
+private int int_value(Instruction i) {
+ result = i.(IntegerOrPointerConstantInstruction).getValue().toInt()
+}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
index e6ad9c86c9bd..bc6ebf2c2958 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
@@ -1665,3 +1665,311 @@ class DataFlowSecondLevelScope extends TDataFlowSecondLevelScope {
/** Gets the second-level scope containing the node `n`, if any. */
DataFlowSecondLevelScope getSecondLevelScope(Node n) { result.getANode() = n }
+
+/**
+ * Module that defines flow through iterators.
+ * For example,
+ * ```cpp
+ * auto it = v.begin();
+ * *it = source();
+ * ...
+ * sink(v[0]);
+ * ```
+ */
+module IteratorFlow {
+ private import codeql.ssa.Ssa as SsaImpl
+ private import semmle.code.cpp.models.interfaces.Iterator as Interface
+ private import semmle.code.cpp.models.implementations.Iterator as Impl
+
+ /**
+ * A variable of some type that can produce an iterator.
+ */
+ class SourceVariable extends Ssa::SourceVariable {
+ SourceVariable() {
+ exists(Interface::GetIteratorFunction gets, Cpp::FunctionInput input, int i |
+ input.isParameterDerefOrQualifierObject(i) and
+ gets.getsIterator(input, _)
+ |
+ this.getType().stripType() = gets.getParameter(i).getType().stripType()
+ or
+ i = -1 and
+ this.getType().stripType() = gets.getDeclaringType()
+ )
+ }
+ }
+
+ private module SsaInput implements SsaImpl::InputSig {
+ import Ssa::InputSigCommon
+
+ class SourceVariable = IteratorFlow::SourceVariable;
+
+ /** A call to function that dereferences an iterator. */
+ private class IteratorPointerDereferenceCall extends CallInstruction {
+ IteratorPointerDereferenceCall() {
+ this.getStaticCallTarget() instanceof Impl::IteratorPointerDereferenceOperator
+ }
+ }
+
+ /** A call to a function that obtains an iterator. */
+ private class GetsIteratorCall extends CallInstruction {
+ GetsIteratorCall() { this.getStaticCallTarget() instanceof Impl::GetIteratorFunction }
+ }
+
+ /** A call to `operator++` or `operator--` on an iterator. */
+ private class IteratorCrementCall extends CallInstruction {
+ IteratorCrementCall() { this.getStaticCallTarget() instanceof Impl::IteratorCrementOperator }
+ }
+
+ /**
+ * Gets an ultimate definition of `def`.
+ *
+ * Note: Unlike `def.getAnUltimateDefinition()` this predicate also
+ * traverses back through iterator increment and decrement operations.
+ */
+ private Ssa::Def getAnUltimateDefinition(Ssa::Def def) {
+ result = def.getAnUltimateDefinition()
+ or
+ exists(IRBlock bb, int i, IteratorCrementCall crementCall, Ssa::SourceVariable sv |
+ crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and
+ sv = def.getSourceVariable() and
+ bb.getInstruction(i) = crementCall and
+ Ssa::ssaDefReachesRead(sv, result.asDef(), bb, i)
+ )
+ }
+
+ /**
+ * Holds if `write` is an instruction that writes to address `address`
+ */
+ private predicate isIteratorWrite(Instruction write, Operand address) {
+ exists(Ssa::DefImpl writeDef, IRBlock bb, int i |
+ writeDef.hasIndexInBlock(bb, i, _) and
+ bb.getInstruction(i) = write and
+ address = writeDef.getAddressOperand()
+ )
+ }
+
+ /**
+ * Holds if `writeToDeref` is a write to an iterator that was obtained
+ * by `beginCall`. That is, the following instruction sequence holds:
+ * ```cpp
+ * it = container.begin(); // or a similar iterator-obtaining function call
+ * ...
+ * *it = value;
+ * ```
+ */
+ private predicate isIteratorStoreInstruction(
+ GetsIteratorCall beginCall, Instruction writeToDeref
+ ) {
+ exists(
+ StoreInstruction beginStore, IRBlock bbStar, int iStar, Ssa::Def def,
+ IteratorPointerDereferenceCall starCall, Ssa::Def ultimate, Operand address
+ |
+ isIteratorWrite(writeToDeref, address) and
+ operandForFullyConvertedCall(address, starCall) and
+ bbStar.getInstruction(iStar) = starCall and
+ Ssa::ssaDefReachesRead(_, def.asDef(), bbStar, iStar) and
+ ultimate = getAnUltimateDefinition*(def) and
+ beginStore = ultimate.getValue().asInstruction() and
+ operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)
+ )
+ }
+
+ /**
+ * Holds if `(bb, i)` contains a write to an iterator that may have been obtained
+ * by calling `begin` (or related functions) on the variable `v`.
+ */
+ predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) {
+ certain = false and
+ exists(GetsIteratorCall beginCall, Instruction writeToDeref, IRBlock bbQual, int iQual |
+ isIteratorStoreInstruction(beginCall, writeToDeref) and
+ bb.getInstruction(i) = writeToDeref and
+ bbQual.getInstruction(iQual) = beginCall and
+ Ssa::variableRead(bbQual, iQual, v, _)
+ )
+ }
+
+ /** Holds if `(bb, i)` reads the container variable `v`. */
+ predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) {
+ Ssa::variableRead(bb, i, v, certain)
+ }
+ }
+
+ private module IteratorSsa = SsaImpl::Make;
+
+ cached
+ private newtype TSsaDef =
+ TDef(IteratorSsa::DefinitionExt def) or
+ TPhi(PhiNode phi)
+
+ abstract private class SsaDef extends TSsaDef {
+ /** Gets a textual representation of this element. */
+ string toString() { none() }
+
+ /** Gets the underlying non-phi definition or use. */
+ IteratorSsa::DefinitionExt asDef() { none() }
+
+ /** Gets the underlying phi node. */
+ PhiNode asPhi() { none() }
+
+ /** Gets the location of this element. */
+ abstract Location getLocation();
+ }
+
+ private class Def extends TDef, SsaDef {
+ IteratorSsa::DefinitionExt def;
+
+ Def() { this = TDef(def) }
+
+ final override IteratorSsa::DefinitionExt asDef() { result = def }
+
+ final override Location getLocation() { result = this.getImpl().getLocation() }
+
+ /** Gets the variable written to by this definition. */
+ final SourceVariable getSourceVariable() { result = def.getSourceVariable() }
+
+ override string toString() { result = def.toString() }
+
+ /**
+ * Holds if this definition (or use) has index `index` in block `block`,
+ * and is a definition (or use) of the variable `sv`.
+ */
+ predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
+ def.definesAt(sv, block, index, _)
+ }
+
+ private Ssa::DefImpl getImpl() {
+ exists(IRBlock bb, int i |
+ this.hasIndexInBlock(bb, i, _) and
+ result.hasIndexInBlock(bb, i)
+ )
+ }
+
+ /** Gets the value written by this definition (i.e., the "right-hand side"). */
+ Node0Impl getValue() { result = this.getImpl().getValue() }
+
+ /** Gets the indirection index of this definition. */
+ int getIndirectionIndex() { result = this.getImpl().getIndirectionIndex() }
+ }
+
+ private class Phi extends TPhi, SsaDef {
+ PhiNode phi;
+
+ Phi() { this = TPhi(phi) }
+
+ final override PhiNode asPhi() { result = phi }
+
+ final override Location getLocation() { result = phi.getBasicBlock().getLocation() }
+
+ override string toString() { result = phi.toString() }
+
+ SsaIteratorNode getNode() { result.getIteratorFlowNode() = phi }
+ }
+
+ private class PhiNode extends IteratorSsa::DefinitionExt {
+ PhiNode() {
+ this instanceof IteratorSsa::PhiNode or
+ this instanceof IteratorSsa::PhiReadNode
+ }
+
+ SsaIteratorNode getNode() { result.getIteratorFlowNode() = this }
+ }
+
+ cached
+ private module IteratorSsaCached {
+ cached
+ predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
+ IteratorSsa::adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
+ or
+ exists(PhiNode phi |
+ IteratorSsa::lastRefRedefExt(_, sv, bb1, i1, phi) and
+ phi.definesAt(sv, bb2, i2, _)
+ )
+ }
+
+ cached
+ Node getAPriorDefinition(IteratorSsa::DefinitionExt next) {
+ exists(IRBlock bb, int i, SourceVariable sv, IteratorSsa::DefinitionExt def |
+ IteratorSsa::lastRefRedefExt(pragma[only_bind_into](def), pragma[only_bind_into](sv),
+ pragma[only_bind_into](bb), pragma[only_bind_into](i), next) and
+ nodeToDefOrUse(result, sv, bb, i, _)
+ )
+ }
+ }
+
+ /** The set of nodes necessary for iterator flow. */
+ class IteratorFlowNode instanceof PhiNode {
+ /** Gets a textual representation of this node. */
+ string toString() { result = super.toString() }
+
+ /** Gets the type of this node. */
+ DataFlowType getType() {
+ exists(Ssa::SourceVariable sv |
+ super.definesAt(sv, _, _, _) and
+ result = sv.getType()
+ )
+ }
+
+ /** Gets the `Declaration` that contains this block. */
+ Declaration getFunction() { result = super.getBasicBlock().getEnclosingFunction() }
+
+ /** Gets the locatino of this node. */
+ Location getLocation() { result = super.getBasicBlock().getLocation() }
+ }
+
+ private import IteratorSsaCached
+
+ private predicate defToNode(Node node, Def def, boolean uncertain) {
+ (
+ nodeHasOperand(node, def.getValue().asOperand(), def.getIndirectionIndex())
+ or
+ nodeHasInstruction(node, def.getValue().asInstruction(), def.getIndirectionIndex())
+ ) and
+ uncertain = false
+ }
+
+ private predicate nodeToDefOrUse(
+ Node node, SourceVariable sv, IRBlock bb, int i, boolean uncertain
+ ) {
+ exists(Def def |
+ def.hasIndexInBlock(bb, i, sv) and
+ defToNode(node, def, uncertain)
+ )
+ or
+ useToNode(bb, i, sv, node) and
+ uncertain = false
+ }
+
+ private predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
+ exists(PhiNode phi |
+ phi.definesAt(sv, bb, i, _) and
+ nodeTo = phi.getNode()
+ )
+ or
+ exists(Ssa::UseImpl use |
+ use.hasIndexInBlock(bb, i, sv) and
+ nodeTo = use.getNode()
+ )
+ }
+
+ /**
+ * Holds if `nodeFrom` flows to `nodeTo` in a single step.
+ */
+ predicate localFlowStep(Node nodeFrom, Node nodeTo) {
+ exists(
+ Node nFrom, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2, boolean uncertain
+ |
+ adjacentDefRead(bb1, i1, sv, bb2, i2) and
+ nodeToDefOrUse(nFrom, sv, bb1, i1, uncertain) and
+ useToNode(bb2, i2, sv, nodeTo)
+ |
+ if uncertain = true
+ then
+ nodeFrom =
+ [
+ nFrom,
+ getAPriorDefinition(any(IteratorSsa::DefinitionExt next | next.definesAt(sv, bb1, i1, _)))
+ ]
+ else nFrom = nodeFrom
+ )
+ }
+}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 94729c47fcb3..dc591dccbb98 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -46,6 +46,7 @@ private newtype TIRDataFlowNode =
Ssa::isModifiableByCall(operand, indirectionIndex)
} or
TSsaPhiNode(Ssa::PhiNode phi) or
+ TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
Ssa::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
} or
@@ -653,6 +654,30 @@ class SsaPhiNode extends Node, TSsaPhiNode {
predicate isPhiRead() { phi.isPhiRead() }
}
+/**
+ * INTERNAL: do not use.
+ *
+ * Dataflow nodes necessary for iterator flow
+ */
+class SsaIteratorNode extends Node, TSsaIteratorNode {
+ IteratorFlow::IteratorFlowNode node;
+
+ SsaIteratorNode() { this = TSsaIteratorNode(node) }
+
+ /** Gets the phi node associated with this node. */
+ IteratorFlow::IteratorFlowNode getIteratorFlowNode() { result = node }
+
+ override Declaration getEnclosingCallable() { result = this.getFunction() }
+
+ override Declaration getFunction() { result = node.getFunction() }
+
+ override DataFlowType getType() { result = node.getType() }
+
+ final override Location getLocationImpl() { result = node.getLocation() }
+
+ override string toStringImpl() { result = node.toString() }
+}
+
/**
* INTERNAL: do not use.
*
@@ -1190,11 +1215,11 @@ class UninitializedNode extends Node {
LocalVariable v;
UninitializedNode() {
- exists(Ssa::Def def |
+ exists(Ssa::Def def, Ssa::SourceVariable sv |
def.getIndirectionIndex() = 0 and
def.getValue().asInstruction() instanceof UninitializedInstruction and
- Ssa::nodeToDefOrUse(this, def, _) and
- v = def.getSourceVariable().getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
+ Ssa::defToNode(this, def, sv, _, _, _) and
+ v = sv.getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
)
}
@@ -2151,6 +2176,8 @@ private module Cached {
// Def-use/Use-use flow
Ssa::ssaFlow(nodeFrom, nodeTo)
or
+ IteratorFlow::localFlowStep(nodeFrom, nodeTo)
+ or
// Operand -> Instruction flow
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
or
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll
index 7eb84aefe3f4..e1512366c709 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll
@@ -9,6 +9,7 @@ private import semmle.code.cpp.models.interfaces.PartialFlow as PartialFlow
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as FIO
private import semmle.code.cpp.ir.internal.IRCppLanguage
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
+private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedInitialization
private import DataFlowPrivate
import SsaInternalsCommon
@@ -102,12 +103,20 @@ predicate hasRawIndirectInstruction(Instruction instr, int indirectionIndex) {
}
cached
-private newtype TDefOrUseImpl =
+private newtype TDefImpl =
TDefAddressImpl(BaseIRVariable v) or
- TDefImpl(BaseSourceVariableInstruction base, Operand address, int indirectionIndex) {
+ TDirectDefImpl(BaseSourceVariableInstruction base, Operand address, int indirectionIndex) {
isDef(_, _, address, base, _, indirectionIndex)
} or
- TUseImpl(BaseSourceVariableInstruction base, Operand operand, int indirectionIndex) {
+ TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
+ // Represents the initial "definition" of a global variable when entering
+ // a function body.
+ isGlobalDefImpl(v, f, _, indirectionIndex)
+ }
+
+cached
+private newtype TUseImpl =
+ TDirectUseImpl(BaseSourceVariableInstruction base, Operand operand, int indirectionIndex) {
isUse(_, operand, base, _, indirectionIndex) and
not isDef(true, _, operand, _, _, _)
} or
@@ -116,21 +125,6 @@ private newtype TDefOrUseImpl =
// the assignment to a global variable isn't ruled out as dead.
isGlobalUse(v, f, _, indirectionIndex)
} or
- TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
- // Represents the initial "definition" of a global variable when entering
- // a function body.
- isGlobalDefImpl(v, f, _, indirectionIndex)
- } or
- TIteratorDef(
- Operand iteratorDerefAddress, BaseSourceVariableInstruction container, int indirectionIndex
- ) {
- isIteratorDef(container, iteratorDerefAddress, _, _, indirectionIndex)
- } or
- TIteratorUse(
- Operand iteratorAddress, BaseSourceVariableInstruction container, int indirectionIndex
- ) {
- isIteratorUse(container, iteratorAddress, _, indirectionIndex)
- } or
TFinalParameterUse(Parameter p, int indirectionIndex) {
underlyingTypeIsModifiableAt(p.getUnderlyingType(), indirectionIndex) and
// Only create an SSA read for the final use of a parameter if there's
@@ -177,7 +171,12 @@ private predicate underlyingTypeIsModifiableAt(Type underlying, int indirectionI
private Indirection getIndirectionForUnspecifiedType(Type t) { result.getType() = t }
-abstract private class DefOrUseImpl extends TDefOrUseImpl {
+abstract class DefImpl extends TDefImpl {
+ int indirectionIndex;
+
+ bindingset[indirectionIndex]
+ DefImpl() { any() }
+
/** Gets a textual representation of this element. */
abstract string toString();
@@ -199,6 +198,9 @@ abstract private class DefOrUseImpl extends TDefOrUseImpl {
/** Gets the location of this element. */
abstract Cpp::Location getLocation();
+ /** Gets the indirection index of this definition. */
+ final int getIndirectionIndex() { result = indirectionIndex }
+
/**
* Gets the index (i.e., the number of loads required) of this
* definition or use.
@@ -207,7 +209,7 @@ abstract private class DefOrUseImpl extends TDefOrUseImpl {
* the enclosing basic block. To obtain this index, use
* `DefOrUseImpl::hasIndexInBlock/2` or `DefOrUseImpl::hasIndexInBlock/3`.
*/
- abstract int getIndirectionIndex();
+ abstract int getIndirection();
/**
* Gets the instruction that computes the base of this definition or use.
@@ -225,17 +227,89 @@ abstract private class DefOrUseImpl extends TDefOrUseImpl {
/** Gets the variable that is defined or used. */
SourceVariable getSourceVariable() {
- exists(BaseSourceVariable v, int ind |
- sourceVariableHasBaseAndIndex(result, v, ind) and
- defOrUseHasSourceVariable(this, v, ind)
+ exists(BaseSourceVariable v, int indirection |
+ sourceVariableHasBaseAndIndex(result, v, indirection) and
+ defHasSourceVariable(this, v, indirection)
)
}
+
+ abstract predicate isCertain();
+
+ abstract Node0Impl getValue();
+
+ Operand getAddressOperand() { none() }
}
-private predicate defOrUseHasSourceVariable(DefOrUseImpl defOrUse, BaseSourceVariable bv, int ind) {
- defHasSourceVariable(defOrUse, bv, ind)
- or
- useHasSourceVariable(defOrUse, bv, ind)
+abstract class UseImpl extends TUseImpl {
+ int indirectionIndex;
+
+ bindingset[indirectionIndex]
+ UseImpl() { any() }
+
+ /** Gets the node associated with this use. */
+ abstract Node getNode();
+
+ /** Gets a textual representation of this element. */
+ abstract string toString();
+
+ /** Gets the block of this definition or use. */
+ final IRBlock getBlock() { this.hasIndexInBlock(result, _) }
+
+ /** Holds if this definition or use has index `index` in block `block`. */
+ abstract predicate hasIndexInBlock(IRBlock block, int index);
+
+ /**
+ * Holds if this definition (or use) has index `index` in block `block`,
+ * and is a definition (or use) of the variable `sv`
+ */
+ final predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
+ this.hasIndexInBlock(block, index) and
+ sv = this.getSourceVariable()
+ }
+
+ /** Gets the location of this element. */
+ abstract Cpp::Location getLocation();
+
+ /**
+ * Gets the index (i.e., the number of loads required) of this
+ * definition or use.
+ *
+ * Note that this is _not_ the definition's (or use's) index in
+ * the enclosing basic block. To obtain this index, use
+ * `DefOrUseImpl::hasIndexInBlock/2` or `DefOrUseImpl::hasIndexInBlock/3`.
+ */
+ abstract int getIndirection();
+
+ /** Gets the indirection index of this use. */
+ final int getIndirectionIndex() { result = indirectionIndex }
+
+ /**
+ * Gets the instruction that computes the base of this definition or use.
+ * This is always a `VariableAddressInstruction` or an `CallInstruction`.
+ */
+ abstract BaseSourceVariableInstruction getBase();
+
+ /**
+ * Gets the base source variable (i.e., the variable without
+ * any indirection) of this definition or use.
+ */
+ final BaseSourceVariable getBaseSourceVariable() {
+ this.getBase().getBaseSourceVariable() = result
+ }
+
+ /** Gets the variable that is defined or used. */
+ SourceVariable getSourceVariable() {
+ exists(BaseSourceVariable v, int indirection |
+ sourceVariableHasBaseAndIndex(result, v, indirection) and
+ useHasSourceVariable(this, v, indirection)
+ )
+ }
+
+ /**
+ * Holds if this use is guaranteed to read the
+ * associated variable.
+ */
+ abstract predicate isCertain();
}
pragma[noinline]
@@ -256,21 +330,15 @@ private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVari
v.getIndirection() = ind
}
-abstract class DefImpl extends DefOrUseImpl {
- int ind;
-
- bindingset[ind]
- DefImpl() { any() }
-
- override int getIndirectionIndex() { result = ind }
-
- override string toString() { result = "Def of " + this.getSourceVariable() }
-
- abstract int getIndirection();
-
- abstract predicate isCertain();
-
- abstract Node0Impl getValue();
+/**
+ * Gets the instruction that computes the address that's used to
+ * initialize `v`.
+ */
+private Instruction getInitializationTargetAddress(IRVariable v) {
+ exists(TranslatedVariableInitialization init |
+ init.getIRVariable() = v and
+ result = init.getTargetAddress()
+ )
}
/** An initial definition of an `IRVariable`'s address. */
@@ -279,9 +347,11 @@ private class DefAddressImpl extends DefImpl, TDefAddressImpl {
DefAddressImpl() {
this = TDefAddressImpl(v) and
- ind = 0
+ indirectionIndex = 0
}
+ override string toString() { result = "Def of &" + v.toString() }
+
final override int getIndirection() { result = 0 }
final override predicate isCertain() { any() }
@@ -289,8 +359,15 @@ private class DefAddressImpl extends DefImpl, TDefAddressImpl {
final override Node0Impl getValue() { none() }
final override predicate hasIndexInBlock(IRBlock block, int index) {
- block = v.getIRVariable().getEnclosingIRFunction().getEntryBlock() and
- index = 0
+ exists(IRVariable var | var = v.getIRVariable() |
+ block.getInstruction(index) = getInitializationTargetAddress(var)
+ or
+ // If there is no translatated element that does initialization of the
+ // variable we place the SSA definition at the entry block of the function.
+ not exists(getInitializationTargetAddress(var)) and
+ block = var.getEnclosingIRFunction().getEntryBlock() and
+ index = 0
+ )
}
override Cpp::Location getLocation() { result = v.getIRVariable().getLocation() }
@@ -303,91 +380,45 @@ private class DefAddressImpl extends DefImpl, TDefAddressImpl {
final override BaseSourceVariableInstruction getBase() { none() }
}
-/**
- * An SSA definition that has an associated `Operand` representing the address
- * that is being written to.
- */
-abstract private class OperandBasedDef extends DefImpl {
+private class DirectDef extends DefImpl, TDirectDefImpl {
Operand address;
+ BaseSourceVariableInstruction base;
- bindingset[ind]
- OperandBasedDef() { any() }
-
- Operand getAddressOperand() { result = address }
+ DirectDef() { this = TDirectDefImpl(base, address, indirectionIndex) }
override Cpp::Location getLocation() { result = this.getAddressOperand().getUse().getLocation() }
final override predicate hasIndexInBlock(IRBlock block, int index) {
this.getAddressOperand().getUse() = block.getInstruction(index)
}
-}
-private class DirectDef extends OperandBasedDef, TDefImpl {
- BaseSourceVariableInstruction base;
+ override string toString() { result = "Def of " + this.getSourceVariable() }
- DirectDef() { this = TDefImpl(base, address, ind) }
+ override Operand getAddressOperand() { result = address }
override BaseSourceVariableInstruction getBase() { result = base }
- override int getIndirection() { isDef(_, _, address, base, result, ind) }
+ override int getIndirection() { isDef(_, _, address, base, result, indirectionIndex) }
override Node0Impl getValue() { isDef(_, result, address, base, _, _) }
- override predicate isCertain() { isDef(true, _, address, base, _, ind) }
+ override predicate isCertain() { isDef(true, _, address, base, _, indirectionIndex) }
}
-private class IteratorDef extends OperandBasedDef, TIteratorDef {
- BaseSourceVariableInstruction container;
-
- IteratorDef() { this = TIteratorDef(address, container, ind) }
-
- override BaseSourceVariableInstruction getBase() { result = container }
-
- override int getIndirection() { isIteratorDef(container, address, _, result, ind) }
-
- override Node0Impl getValue() { isIteratorDef(container, address, result, _, _) }
-
- override predicate isCertain() { none() }
-}
-
-abstract class UseImpl extends DefOrUseImpl {
- int ind;
-
- bindingset[ind]
- UseImpl() { any() }
-
- /** Gets the node associated with this use. */
- abstract Node getNode();
-
- override string toString() { result = "Use of " + this.getSourceVariable() }
-
- /** Gets the indirection index of this use. */
- final override int getIndirectionIndex() { result = ind }
-
- /** Gets the number of loads that precedence this use. */
- abstract int getIndirection();
-
- /**
- * Holds if this use is guaranteed to read the
- * associated variable.
- */
- abstract predicate isCertain();
-}
-
-abstract private class OperandBasedUse extends UseImpl {
+private class DirectUseImpl extends UseImpl, TDirectUseImpl {
Operand operand;
BaseSourceVariableInstruction base;
- bindingset[ind]
- OperandBasedUse() { any() }
+ DirectUseImpl() { this = TDirectUseImpl(base, operand, indirectionIndex) }
+
+ override string toString() { result = "Use of " + this.getSourceVariable() }
final override predicate hasIndexInBlock(IRBlock block, int index) {
// See the comment in `ssa0`'s `OperandBasedUse` for an explanation of this
// predicate's implementation.
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
then
- exists(Operand op, int indirectionIndex, int indirection |
- indirectionIndex = this.getIndirectionIndex() and
+ exists(Operand op, int indirection |
indirection = this.getIndirection() and
op =
min(Operand cand, int i |
@@ -406,26 +437,12 @@ abstract private class OperandBasedUse extends UseImpl {
final Operand getOperand() { result = operand }
final override Cpp::Location getLocation() { result = operand.getLocation() }
-}
-private class DirectUse extends OperandBasedUse, TUseImpl {
- DirectUse() { this = TUseImpl(base, operand, ind) }
+ override int getIndirection() { isUse(_, operand, base, result, indirectionIndex) }
- override int getIndirection() { isUse(_, operand, base, result, ind) }
+ override predicate isCertain() { isUse(true, operand, base, _, indirectionIndex) }
- override predicate isCertain() { isUse(true, operand, base, _, ind) }
-
- override Node getNode() { nodeHasOperand(result, operand, ind) }
-}
-
-private class IteratorUse extends OperandBasedUse, TIteratorUse {
- IteratorUse() { this = TIteratorUse(operand, base, ind) }
-
- override int getIndirection() { isIteratorUse(base, operand, result, ind) }
-
- override predicate isCertain() { none() }
-
- override Node getNode() { nodeHasOperand(result, operand, ind) }
+ override Node getNode() { nodeHasOperand(result, operand, indirectionIndex) }
}
pragma[nomagic]
@@ -439,15 +456,17 @@ private predicate finalParameterNodeHasParameterAndIndex(
class FinalParameterUse extends UseImpl, TFinalParameterUse {
Parameter p;
- FinalParameterUse() { this = TFinalParameterUse(p, ind) }
+ FinalParameterUse() { this = TFinalParameterUse(p, indirectionIndex) }
+
+ override string toString() { result = "Use of " + p.toString() }
Parameter getParameter() { result = p }
int getArgumentIndex() { result = p.getIndex() }
- override Node getNode() { finalParameterNodeHasParameterAndIndex(result, p, ind) }
+ override Node getNode() { finalParameterNodeHasParameterAndIndex(result, p, indirectionIndex) }
- override int getIndirection() { result = ind + 1 }
+ override int getIndirection() { result = indirectionIndex + 1 }
override predicate isCertain() { any() }
@@ -544,11 +563,13 @@ class GlobalUse extends UseImpl, TGlobalUse {
GlobalLikeVariable global;
IRFunction f;
- GlobalUse() { this = TGlobalUse(global, f, ind) }
+ GlobalUse() { this = TGlobalUse(global, f, indirectionIndex) }
+
+ override string toString() { result = "Use of " + global }
override FinalGlobalValue getNode() { result.getGlobalUse() = this }
- override int getIndirection() { isGlobalUse(global, f, result, ind) }
+ override int getIndirection() { isGlobalUse(global, f, result, indirectionIndex) }
/** Gets the global variable associated with this use. */
GlobalLikeVariable getVariable() { result = global }
@@ -598,10 +619,9 @@ class GlobalUse extends UseImpl, TGlobalUse {
*
* See the QLDoc for `GlobalUse` for how this is used.
*/
-class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
+class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
GlobalLikeVariable global;
IRFunction f;
- int indirectionIndex;
GlobalDefImpl() { this = TGlobalDefImpl(global, f, indirectionIndex) }
@@ -611,9 +631,6 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
/** Gets the `IRFunction` whose body is evaluated after this definition. */
IRFunction getIRFunction() { result = f }
- /** Gets the global variable associated with this definition. */
- override int getIndirectionIndex() { result = indirectionIndex }
-
/** Holds if this definition or use has index `index` in block `block`. */
final override predicate hasIndexInBlock(IRBlock block, int index) {
exists(EnterFunctionInstruction enter |
@@ -627,7 +644,11 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
sourceVariableIsGlobal(result, global, f, this.getIndirection())
}
- int getIndirection() { result = indirectionIndex }
+ override int getIndirection() { result = indirectionIndex }
+
+ override Node0Impl getValue() { none() }
+
+ override predicate isCertain() { any() }
/**
* Gets the type of this definition after specifiers have been deeply
@@ -648,60 +669,30 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
}
/**
- * Holds if `defOrUse1` is a definition which is first read by `use`,
- * or if `defOrUse1` is a use and `use` is a next subsequent use.
- *
- * In both cases, `use` can either be an explicit use written in the
- * source file, or it can be a phi node as computed by the SSA library.
+ * Holds if there is a definition or access at index `i1` in basic block `bb1`
+ * and the next subsequent read is at index `i2` in basic block `bb2`.
*/
-predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
- exists(IRBlock bb1, int i1, SourceVariable v |
- defOrUse1
- .asDefOrUse()
- .hasIndexInBlock(pragma[only_bind_out](bb1), pragma[only_bind_out](i1),
- pragma[only_bind_out](v))
- |
- exists(IRBlock bb2, int i2, DefinitionExt def |
- adjacentDefReadExt(pragma[only_bind_into](def), pragma[only_bind_into](bb1),
- pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
- def.getSourceVariable() = v and
- use.asDefOrUse().(UseImpl).hasIndexInBlock(bb2, i2, v)
- )
- or
- exists(PhiNode phi |
- lastRefRedefExt(_, bb1, i1, phi) and
- use.asPhi() = phi and
- phi.getSourceVariable() = pragma[only_bind_into](v)
- )
+predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
+ adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
+ or
+ exists(PhiNode phi |
+ lastRefRedefExt(_, sv, bb1, i1, phi) and
+ phi.definesAt(sv, bb2, i2, _)
)
}
-/**
- * Holds if `globalDef` represents the initial definition of a global variable that
- * flows to `useOrPhi`.
- */
-private predicate globalDefToUse(GlobalDef globalDef, UseOrPhi useOrPhi) {
- exists(IRBlock bb1, int i1, SourceVariable v |
- globalDef
- .hasIndexInBlock(pragma[only_bind_out](bb1), pragma[only_bind_out](i1),
- pragma[only_bind_out](v))
- |
- exists(IRBlock bb2, int i2 |
- adjacentDefReadExt(_, pragma[only_bind_into](bb1), pragma[only_bind_into](i1),
- pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
- useOrPhi.asDefOrUse().hasIndexInBlock(bb2, i2, v)
- )
- or
- exists(PhiNode phi |
- lastRefRedefExt(_, bb1, i1, phi) and
- useOrPhi.asPhi() = phi and
- phi.getSourceVariable() = pragma[only_bind_into](v)
- )
+predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
+ exists(Phi phi |
+ phi.asPhi().definesAt(sv, bb, i, _) and
+ nodeTo = phi.getNode()
+ )
+ or
+ exists(UseImpl use |
+ use.hasIndexInBlock(bb, i, sv) and
+ nodeTo = use.getNode()
)
}
-private predicate useToNode(UseOrPhi use, Node nodeTo) { use.getNode() = nodeTo }
-
pragma[noinline]
predicate outNodeHasAddressAndIndex(
IndirectArgumentOutNode out, Operand address, int indirectionIndex
@@ -710,11 +701,19 @@ predicate outNodeHasAddressAndIndex(
out.getIndirectionIndex() = indirectionIndex
}
-private predicate defToNode(Node nodeFrom, Def def, boolean uncertain) {
+/**
+ * INTERNAL: Do not use.
+ *
+ * Holds if `node` is the node that corresponds to the definition of `def`.
+ */
+predicate defToNode(Node node, Def def, SourceVariable sv, IRBlock bb, int i, boolean uncertain) {
+ def.hasIndexInBlock(bb, i, sv) and
(
- nodeHasOperand(nodeFrom, def.getValue().asOperand(), def.getIndirectionIndex())
+ nodeHasOperand(node, def.getValue().asOperand(), def.getIndirectionIndex())
or
- nodeHasInstruction(nodeFrom, def.getValue().asInstruction(), def.getIndirectionIndex())
+ nodeHasInstruction(node, def.getValue().asInstruction(), def.getIndirectionIndex())
+ or
+ node.(InitialGlobalValue).getGlobalDef() = def
) and
if def.isCertain() then uncertain = false else uncertain = true
}
@@ -722,14 +721,16 @@ private predicate defToNode(Node nodeFrom, Def def, boolean uncertain) {
/**
* INTERNAL: Do not use.
*
- * Holds if `nodeFrom` is the node that correspond to the definition or use `defOrUse`.
+ * Holds if `node` is the node that corresponds to the definition or use at
+ * index `i` in block `bb` of `sv`.
+ *
+ * `uncertain` is `true` if this is an uncertain definition.
*/
-predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse, boolean uncertain) {
- // Node -> Def
- defToNode(nodeFrom, defOrUse, uncertain)
+predicate nodeToDefOrUse(Node node, SourceVariable sv, IRBlock bb, int i, boolean uncertain) {
+ defToNode(node, _, sv, bb, i, uncertain)
or
// Node -> Use
- useToNode(defOrUse, nodeFrom) and
+ useToNode(bb, i, sv, node) and
uncertain = false
}
@@ -738,9 +739,9 @@ predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse, boolean uncertain)
* only holds when there is no use-use relation out of `nTo`.
*/
private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
- not exists(UseOrPhi defOrUse |
- nodeToDefOrUse(nTo, defOrUse, _) and
- adjacentDefRead(defOrUse, _)
+ not exists(SourceVariable sv, IRBlock bb2, int i2 |
+ nodeToDefOrUse(nTo, sv, bb2, i2, _) and
+ adjacentDefRead(bb2, i2, sv, _, _)
) and
(
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
@@ -774,60 +775,39 @@ private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
* So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the
* first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`.
*/
-private predicate adjustForPointerArith(PostUpdateNode pun, UseOrPhi use) {
- exists(DefOrUse defOrUse, Node adjusted |
+private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, IRBlock bb2, int i2) {
+ exists(IRBlock bb1, int i1, Node adjusted |
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
- nodeToDefOrUse(adjusted, defOrUse, _) and
- adjacentDefRead(defOrUse, use)
+ nodeToDefOrUse(adjusted, sv, bb1, i1, _) and
+ adjacentDefRead(bb1, i1, sv, bb2, i2)
)
}
/**
- * Holds if `nodeFrom` flows to `nodeTo` because there is `def-use` or
- * `use-use` flow from `defOrUse` to `use`.
+ * Holds if there should be flow from `nodeFrom` to `nodeTo` because
+ * `nodeFrom` is a definition or use of `sv` at index `i1` at basic
+ * block `bb1`.
*
- * `uncertain` is `true` if the `defOrUse` is an uncertain definition.
+ * `uncertain` is `true` if `(bb1, i1)` is a definition, and that definition
+ * is _not_ guaranteed to overwrite the entire allocation.
*/
-private predicate localSsaFlow(
- SsaDefOrUse defOrUse, Node nodeFrom, UseOrPhi use, Node nodeTo, boolean uncertain
+private predicate ssaFlowImpl(
+ IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain
) {
- nodeToDefOrUse(nodeFrom, defOrUse, uncertain) and
- adjacentDefRead(defOrUse, use) and
- useToNode(use, nodeTo) and
+ exists(IRBlock bb2, int i2 |
+ nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
+ adjacentDefRead(bb1, i1, sv, bb2, i2) and
+ useToNode(bb2, i2, sv, nodeTo)
+ ) and
nodeFrom != nodeTo
}
-private predicate ssaFlowImpl(SsaDefOrUse defOrUse, Node nodeFrom, Node nodeTo, boolean uncertain) {
- exists(UseOrPhi use |
- localSsaFlow(defOrUse, nodeFrom, use, nodeTo, uncertain)
- or
- // Initial global variable value to a first use
- nodeFrom.(InitialGlobalValue).getGlobalDef() = defOrUse and
- globalDefToUse(defOrUse, use) and
- useToNode(use, nodeTo) and
- uncertain = false
- )
-}
-
-/**
- * Holds if `def` is the corresponding definition of
- * the SSA library's `definition`.
- */
-private DefinitionExt ssaDefinition(Def def) {
- exists(IRBlock block, int i, SourceVariable sv |
- def.hasIndexInBlock(block, i, sv) and
- result.definesAt(sv, block, i, _)
- )
-}
-
/** Gets a node that represents the prior definition of `node`. */
-private Node getAPriorDefinition(SsaDefOrUse defOrUse) {
- exists(IRBlock bb, int i, SourceVariable sv, DefinitionExt def, DefOrUse defOrUse0 |
- lastRefRedefExt(pragma[only_bind_into](def), pragma[only_bind_into](bb),
- pragma[only_bind_into](i), ssaDefinition(defOrUse)) and
- def.getSourceVariable() = sv and
- defOrUse0.hasIndexInBlock(bb, i, sv) and
- nodeToDefOrUse(result, defOrUse0, _)
+private Node getAPriorDefinition(DefinitionExt next) {
+ exists(IRBlock bb, int i, SourceVariable sv |
+ lastRefRedefExt(_, pragma[only_bind_into](sv), pragma[only_bind_into](bb),
+ pragma[only_bind_into](i), next) and
+ nodeToDefOrUse(result, sv, bb, i, _)
)
}
@@ -879,12 +859,16 @@ private predicate modeledFlowBarrier(Node n) {
/** Holds if there is def-use or use-use flow from `nodeFrom` to `nodeTo`. */
predicate ssaFlow(Node nodeFrom, Node nodeTo) {
- exists(Node nFrom, boolean uncertain, SsaDefOrUse defOrUse |
- ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain) and
+ exists(Node nFrom, boolean uncertain, IRBlock bb, int i, SourceVariable sv |
+ ssaFlowImpl(bb, i, sv, nFrom, nodeTo, uncertain) and
not modeledFlowBarrier(nFrom) and
nodeFrom != nodeTo
|
- if uncertain = true then nodeFrom = [nFrom, getAPriorDefinition(defOrUse)] else nodeFrom = nFrom
+ if uncertain = true
+ then
+ nodeFrom =
+ [nFrom, getAPriorDefinition(any(DefinitionExt next | next.definesAt(sv, bb, i, _)))]
+ else nodeFrom = nFrom
)
}
@@ -929,15 +913,15 @@ private predicate isArgumentOfCallable(DataFlowCall call, Node n) {
* Holds if there is use-use flow from `pun`'s pre-update node to `n`.
*/
private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) {
- exists(UseOrPhi use |
- adjustForPointerArith(pun, use) and
- useToNode(use, n)
+ exists(SourceVariable sv, IRBlock bb2, int i2 |
+ adjustForPointerArith(pun, sv, bb2, i2) and
+ useToNode(bb2, i2, sv, n)
)
}
private predicate stepUntilNotInCall(DataFlowCall call, Node n1, Node n2) {
isArgumentOfCallable(call, n1) and
- exists(Node mid | localSsaFlow(_, n1, _, mid, _) |
+ exists(Node mid | ssaFlowImpl(_, _, _, n1, mid, _) |
isArgumentOfCallable(call, mid) and
stepUntilNotInCall(call, mid, n2)
or
@@ -984,35 +968,13 @@ predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
)
}
-/**
- * Holds if `use` is a use of `sv` and is a next adjacent use of `phi` in
- * index `i1` in basic block `bb1`.
- *
- * This predicate exists to prevent an early join of `adjacentDefRead` with `definesAt`.
- */
-pragma[nomagic]
-private predicate fromPhiNodeToUse(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use) {
- exists(IRBlock bb2, int i2 |
- use.asDefOrUse().hasIndexInBlock(bb2, i2, sv) and
- adjacentDefReadExt(pragma[only_bind_into](phi), pragma[only_bind_into](bb1),
- pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2))
- )
-}
-
/** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
- exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use |
+ exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2 |
phi = nodeFrom.getPhiNode() and
phi.definesAt(sv, bb1, i1, _) and
- useToNode(use, nodeTo)
- |
- fromPhiNodeToUse(phi, sv, bb1, i1, use)
- or
- exists(PhiNode phiTo |
- phi != phiTo and
- lastRefRedefExt(phi, bb1, i1, phiTo) and
- nodeTo.(SsaPhiNode).getPhiNode() = phiTo
- )
+ adjacentDefRead(bb1, i1, sv, bb2, i2) and
+ useToNode(bb2, i2, sv, nodeTo)
)
}
@@ -1077,8 +1039,10 @@ module SsaCached {
* path between them without any read of `def`.
*/
cached
- predicate adjacentDefReadExt(DefinitionExt def, IRBlock bb1, int i1, IRBlock bb2, int i2) {
- SsaImpl::adjacentDefReadExt(def, _, bb1, i1, bb2, i2)
+ predicate adjacentDefReadExt(
+ DefinitionExt def, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2
+ ) {
+ SsaImpl::adjacentDefReadExt(def, sv, bb1, i1, bb2, i2)
}
/**
@@ -1087,32 +1051,38 @@ module SsaCached {
* without passing through another read or write.
*/
cached
- predicate lastRefRedefExt(DefinitionExt def, IRBlock bb, int i, DefinitionExt next) {
- SsaImpl::lastRefRedefExt(def, _, bb, i, next)
+ predicate lastRefRedefExt(
+ DefinitionExt def, SourceVariable sv, IRBlock bb, int i, DefinitionExt next
+ ) {
+ SsaImpl::lastRefRedefExt(def, sv, bb, i, next)
}
+
+ cached
+ Definition phiHasInputFromBlock(PhiNode phi, IRBlock bb) {
+ SsaImpl::phiHasInputFromBlock(phi, result, bb)
+ }
+
+ cached
+ predicate ssaDefReachesRead(SourceVariable v, Definition def, IRBlock bb, int i) {
+ SsaImpl::ssaDefReachesRead(v, def, bb, i)
+ }
+
+ predicate variableRead = SsaInput::variableRead/4;
+
+ predicate variableWrite = SsaInput::variableWrite/4;
}
cached
-private newtype TSsaDefOrUse =
- TDefOrUse(DefOrUseImpl defOrUse) {
- defOrUse instanceof UseImpl
- or
- // Like in the pruning stage, we only include definition that's live after the
- // write as the final definitions computed by SSA.
- exists(DefinitionExt def, SourceVariable sv, IRBlock bb, int i |
- def.definesAt(sv, bb, i, _) and
- defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv)
- )
- } or
- TPhi(PhiNode phi) or
- TGlobalDef(GlobalDefImpl global)
+private newtype TSsaDef =
+ TDef(DefinitionExt def) or
+ TPhi(PhiNode phi)
-abstract private class SsaDefOrUse extends TSsaDefOrUse {
+abstract private class SsaDef extends TSsaDef {
/** Gets a textual representation of this element. */
string toString() { none() }
/** Gets the underlying non-phi definition or use. */
- DefOrUseImpl asDefOrUse() { none() }
+ DefinitionExt asDef() { none() }
/** Gets the underlying phi node. */
PhiNode asPhi() { none() }
@@ -1121,52 +1091,97 @@ abstract private class SsaDefOrUse extends TSsaDefOrUse {
abstract Location getLocation();
}
-class DefOrUse extends TDefOrUse, SsaDefOrUse {
- DefOrUseImpl defOrUse;
-
- DefOrUse() { this = TDefOrUse(defOrUse) }
+abstract class Def extends SsaDef, TDef {
+ DefinitionExt def;
- final override DefOrUseImpl asDefOrUse() { result = defOrUse }
+ Def() { this = TDef(def) }
- final override Location getLocation() { result = defOrUse.getLocation() }
+ final override DefinitionExt asDef() { result = def }
- final SourceVariable getSourceVariable() { result = defOrUse.getSourceVariable() }
+ /** Gets the source variable underlying this SSA definition. */
+ final SourceVariable getSourceVariable() { result = def.getSourceVariable() }
- override string toString() { result = defOrUse.toString() }
+ override string toString() { result = def.toString() }
/**
* Holds if this definition (or use) has index `index` in block `block`,
* and is a definition (or use) of the variable `sv`.
*/
predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
- defOrUse.hasIndexInBlock(block, index, sv)
+ def.definesAt(sv, block, index, _)
}
-}
-class GlobalDef extends TGlobalDef, SsaDefOrUse {
- GlobalDefImpl global;
+ /** Gets the value written by this definition, if any. */
+ Node0Impl getValue() { none() }
- GlobalDef() { this = TGlobalDef(global) }
+ /**
+ * Holds if this definition is guaranteed to overwrite the entire
+ * destination's allocation.
+ */
+ abstract predicate isCertain();
- /** Gets the location of this definition. */
- final override Location getLocation() { result = global.getLocation() }
+ /** Gets the address operand written to by this definition. */
+ Operand getAddressOperand() { none() }
- /** Gets a textual representation of this definition. */
- override string toString() { result = global.toString() }
+ /** Gets the address written to by this definition. */
+ final Instruction getAddress() { result = this.getAddressOperand().getDef() }
+
+ /** Gets the indirection index of this definition. */
+ abstract int getIndirectionIndex();
/**
- * Holds if this definition has index `index` in block `block`, and
- * is a definition of the variable `sv`.
+ * Gets the indirection level that this definition is writing to.
+ * For instance, `x = y` is a definition of `x` at indirection level 1 and
+ * `*x = y` is a definition of `x` at indirection level 2.
*/
- predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
- global.hasIndexInBlock(block, index, sv)
+ abstract int getIndirection();
+
+ /**
+ * Gets a definition that ultimately defines this SSA definition and is not
+ * itself a phi node.
+ */
+ Def getAnUltimateDefinition() { result.asDef() = def.getAnUltimateDefinition() }
+}
+
+private predicate isGlobal(DefinitionExt def, GlobalDefImpl global) {
+ exists(SourceVariable sv, IRBlock bb, int i |
+ def.definesAt(sv, bb, i, _) and
+ global.hasIndexInBlock(bb, i, sv)
+ )
+}
+
+private class NonGlobalDef extends Def {
+ NonGlobalDef() { not isGlobal(def, _) }
+
+ final override Location getLocation() { result = this.getImpl().getLocation() }
+
+ private DefImpl getImpl() {
+ exists(SourceVariable sv, IRBlock bb, int i |
+ this.hasIndexInBlock(bb, i, sv) and
+ result.hasIndexInBlock(bb, i, sv)
+ )
}
- /** Gets the indirection index of this definition. */
- int getIndirection() { result = global.getIndirection() }
+ override Node0Impl getValue() { result = this.getImpl().getValue() }
- /** Gets the indirection index of this definition. */
- int getIndirectionIndex() { result = global.getIndirectionIndex() }
+ override predicate isCertain() { this.getImpl().isCertain() }
+
+ override Operand getAddressOperand() { result = this.getImpl().getAddressOperand() }
+
+ override int getIndirectionIndex() { result = this.getImpl().getIndirectionIndex() }
+
+ override int getIndirection() { result = this.getImpl().getIndirection() }
+}
+
+class GlobalDef extends Def {
+ GlobalDefImpl global;
+
+ GlobalDef() { isGlobal(def, global) }
+
+ /** Gets a textual representation of this definition. */
+ override string toString() { result = global.toString() }
+
+ final override Location getLocation() { result = global.getLocation() }
/**
* Gets the type of this definition after specifiers have been deeply stripped
@@ -1184,9 +1199,15 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
/** Gets the global variable associated with this definition. */
GlobalLikeVariable getVariable() { result = global.getVariable() }
+
+ override predicate isCertain() { any() }
+
+ final override int getIndirectionIndex() { result = global.getIndirectionIndex() }
+
+ final override int getIndirection() { result = global.getIndirection() }
}
-class Phi extends TPhi, SsaDefOrUse {
+class Phi extends TPhi, SsaDef {
PhiNode phi;
Phi() { this = TPhi(phi) }
@@ -1198,64 +1219,19 @@ class Phi extends TPhi, SsaDefOrUse {
override string toString() { result = "Phi" }
SsaPhiNode getNode() { result.getPhiNode() = phi }
-}
-class UseOrPhi extends SsaDefOrUse {
- UseOrPhi() {
- this.asDefOrUse() instanceof UseImpl
- or
- this instanceof Phi
- }
-
- final override Location getLocation() {
- result = this.asDefOrUse().getLocation() or result = this.(Phi).getLocation()
- }
+ predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlock(phi, bb) }
- final Node getNode() {
- result = this.(Phi).getNode()
- or
- result = this.asDefOrUse().(UseImpl).getNode()
- }
-}
-
-class Def extends DefOrUse {
- override DefImpl defOrUse;
-
- Operand getAddressOperand() { result = defOrUse.(OperandBasedDef).getAddressOperand() }
-
- Instruction getAddress() { result = this.getAddressOperand().getDef() }
-
- /**
- * Gets the indirection index of this definition.
- *
- * This predicate ensures that joins go from `defOrUse` to the result
- * instead of the other way around.
- */
- pragma[inline]
- int getIndirectionIndex() {
- pragma[only_bind_into](result) = pragma[only_bind_out](defOrUse).getIndirectionIndex()
- }
-
- /**
- * Gets the indirection level that this definition is writing to.
- * For instance, `x = y` is a definition of `x` at indirection level 1 and
- * `*x = y` is a definition of `x` at indirection level 2.
- *
- * This predicate ensures that joins go from `defOrUse` to the result
- * instead of the other way around.
- */
- pragma[inline]
- int getIndirection() {
- pragma[only_bind_into](result) = pragma[only_bind_out](defOrUse).getIndirection()
- }
-
- Node0Impl getValue() { result = defOrUse.getValue() }
-
- predicate isCertain() { defOrUse.isCertain() }
+ final Definition getAnInput() { this.hasInputFromBlock(result, _) }
}
private module SsaImpl = SsaImplCommon::Make;
+/**
+ * An static single assignment (SSA) phi node.
+ *
+ * This is either a normal phi node or a phi-read node.
+ */
class PhiNode extends SsaImpl::DefinitionExt {
PhiNode() {
this instanceof SsaImpl::PhiNode or
@@ -1269,10 +1245,30 @@ class PhiNode extends SsaImpl::DefinitionExt {
* on reads instead of writes.
*/
predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode }
+
+ /** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */
+ predicate hasInputFromBlock(Definition inp, IRBlock bb) {
+ inp = SsaCached::phiHasInputFromBlock(this, bb)
+ }
+
+ /** Gets a definition that is an input to this phi node. */
+ final Definition getAnInput() { this.hasInputFromBlock(result, _) }
}
-class DefinitionExt = SsaImpl::DefinitionExt;
+/** An static single assignment (SSA) definition. */
+class DefinitionExt extends SsaImpl::DefinitionExt {
+ private Definition getAPhiInputOrPriorDefinition() { result = this.(PhiNode).getAnInput() }
+
+ /**
+ * Gets a definition that ultimately defines this SSA definition and is
+ * not itself a phi node.
+ */
+ final DefinitionExt getAnUltimateDefinition() {
+ result = this.getAPhiInputOrPriorDefinition*() and
+ not result instanceof PhiNode
+ }
+}
-class UncertainWriteDefinition = SsaImpl::UncertainWriteDefinition;
+class Definition = SsaImpl::Definition;
import SsaCached
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll
index 7e5b4de8122c..0920e5a38657 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll
@@ -246,14 +246,6 @@ private module IteratorIndirections {
baseType = super.getValueType()
}
- override predicate isAdditionalDereference(Instruction deref, Operand address) {
- exists(CallInstruction call |
- operandForFullyConvertedCall(getAUse(deref), call) and
- this = call.getStaticCallTarget().getClassAndName("operator*") and
- address = call.getThisArgumentOperand()
- )
- }
-
override predicate isAdditionalWrite(Node0Impl value, Operand address, boolean certain) {
exists(CallInstruction call | call.getArgumentOperand(0) = value.asOperand() |
this = call.getStaticCallTarget().getClassAndName("operator=") and
@@ -262,16 +254,6 @@ private module IteratorIndirections {
)
}
- override predicate isAdditionalTaintStep(Node node1, Node node2) {
- exists(CallInstruction call |
- // Taint through `operator+=` and `operator-=` on iterators.
- call.getStaticCallTarget() instanceof Iterator::IteratorAssignArithmeticOperator and
- node2.(IndirectArgumentOutNode).getPreUpdateNode() = node1 and
- node1.(IndirectOperand).hasOperandAndIndirectionIndex(call.getArgumentOperand(0), _) and
- node1.getType().getUnspecifiedType() = this
- )
- }
-
override predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
// This is a bit annoying: Consider the following snippet:
// ```
@@ -589,230 +571,6 @@ private class BaseCallInstruction extends BaseSourceVariableInstruction, CallIns
cached
private module Cached {
- private import semmle.code.cpp.models.interfaces.Iterator as Interfaces
- private import semmle.code.cpp.models.implementations.Iterator as Iterator
- private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as IO
-
- /**
- * Holds if `next` is a instruction with a memory result that potentially
- * updates the memory produced by `prev`.
- */
- private predicate memorySucc(Instruction prev, Instruction next) {
- prev = next.(ChiInstruction).getTotal()
- or
- // Phi inputs can be inexact.
- prev = next.(PhiInstruction).getAnInputOperand().getAnyDef()
- or
- prev = next.(CopyInstruction).getSourceValue()
- or
- exists(ReadSideEffectInstruction read |
- next = read.getPrimaryInstruction() and
- isAdditionalConversionFlow(_, next) and
- prev = read.getSideEffectOperand().getAnyDef()
- )
- }
-
- /**
- * Holds if `iteratorDerefAddress` is an address of an iterator dereference (i.e., `*it`)
- * that is used for a write operation that writes the value `value`. The `memory` instruction
- * represents the memory that the IR's SSA analysis determined was read by the call to `operator*`.
- *
- * The `numberOfLoads` integer represents the number of dereferences this write corresponds to
- * on the underlying container that produced the iterator.
- */
- private predicate isChiAfterIteratorDef(
- Instruction memory, Operand iteratorDerefAddress, Node0Impl value, int numberOfLoads
- ) {
- exists(
- BaseSourceVariableInstruction iteratorBase, ReadSideEffectInstruction read,
- Operand iteratorAddress
- |
- numberOfLoads >= 0 and
- isDef(_, value, iteratorDerefAddress, iteratorBase, numberOfLoads + 2, 0) and
- isUse(_, iteratorAddress, iteratorBase, numberOfLoads + 1, 0) and
- iteratorBase.getResultType() instanceof Interfaces::Iterator and
- isDereference(iteratorAddress.getDef(), read.getArgumentDef().getAUse(), _) and
- memory = read.getSideEffectOperand().getAnyDef()
- )
- }
-
- private predicate isSource(Instruction instr, Operand iteratorAddress, int numberOfLoads) {
- getAUse(instr) = iteratorAddress and
- exists(BaseSourceVariableInstruction iteratorBase |
- iteratorBase.getResultType() instanceof Interfaces::Iterator and
- not iteratorBase.getResultType() instanceof Cpp::PointerType and
- isUse(_, iteratorAddress, iteratorBase, numberOfLoads - 1, 0)
- )
- }
-
- private predicate isSink(Instruction instr, CallInstruction call) {
- getAUse(instr).(ArgumentOperand).getCall() = call and
- // Only include operations that may modify the object that the iterator points to.
- // The following is a non-exhaustive list of things that may modify the value of the
- // iterator, but never the value of what the iterator points to.
- // The more things we can exclude here, the faster the small dataflow-like analysis
- // done by `convertsIntoArgument` will converge.
- not exists(Function f | f = call.getStaticCallTarget() |
- f instanceof Iterator::IteratorCrementOperator or
- f instanceof Iterator::IteratorBinaryArithmeticOperator or
- f instanceof Iterator::IteratorAssignArithmeticOperator or
- f instanceof Iterator::IteratorCrementMemberOperator or
- f instanceof Iterator::IteratorBinaryArithmeticMemberOperator or
- f instanceof Iterator::IteratorAssignArithmeticMemberOperator or
- f instanceof Iterator::IteratorAssignmentMemberOperator
- )
- }
-
- private predicate convertsIntoArgumentFwd(Instruction instr) {
- isSource(instr, _, _)
- or
- exists(Instruction prev | convertsIntoArgumentFwd(prev) |
- conversionFlow(unique( | | getAUse(prev)), instr, false, _)
- )
- }
-
- private predicate convertsIntoArgumentRev(Instruction instr) {
- convertsIntoArgumentFwd(instr) and
- (
- isSink(instr, _)
- or
- exists(Instruction next | convertsIntoArgumentRev(next) |
- conversionFlow(unique( | | getAUse(instr)), next, false, _)
- )
- )
- }
-
- private predicate convertsIntoArgument(
- Operand iteratorAddress, CallInstruction call, int numberOfLoads
- ) {
- exists(Instruction iteratorAddressDef |
- isSource(iteratorAddressDef, iteratorAddress, numberOfLoads) and
- isSink(iteratorAddressDef, call) and
- convertsIntoArgumentRev(pragma[only_bind_into](iteratorAddressDef))
- )
- }
-
- private predicate isChiAfterIteratorArgument(
- Instruction memory, Operand iteratorAddress, int numberOfLoads
- ) {
- // Ideally, `iteratorAddress` would be an `ArgumentOperand`, but there might be
- // various conversions applied to it before it becomes an argument.
- // So we do a small amount of flow to find the call that the iterator is passed to.
- exists(CallInstruction call | convertsIntoArgument(iteratorAddress, call, numberOfLoads) |
- exists(ReadSideEffectInstruction read |
- read.getPrimaryInstruction() = call and
- read.getSideEffectOperand().getAnyDef() = memory
- )
- or
- exists(LoadInstruction load |
- iteratorAddress.getDef() = load and
- memory = load.getSourceValueOperand().getAnyDef()
- )
- )
- }
-
- /**
- * Holds if `iterator` is a `StoreInstruction` that stores the result of some function
- * returning an iterator into an address computed started at `containerBase`.
- *
- * For example, given a declaration like `std::vector::iterator it = v.begin()`,
- * the `iterator` will be the `StoreInstruction` generated by the write to `it`, and
- * `containerBase` will be the address of `v`.
- */
- private predicate isChiAfterBegin(
- BaseSourceVariableInstruction containerBase, StoreInstruction iterator
- ) {
- exists(
- CallInstruction getIterator, Iterator::GetIteratorFunction getIteratorFunction,
- IO::FunctionInput input, int i
- |
- getIterator = iterator.getSourceValue() and
- getIteratorFunction = getIterator.getStaticCallTarget() and
- getIteratorFunction.getsIterator(input, _) and
- isDef(_, any(Node0Impl n | n.asInstruction() = iterator), _, _, 1, 0) and
- input.isParameterDerefOrQualifierObject(i) and
- isUse(_, getIterator.getArgumentOperand(i), containerBase, 0, 0)
- )
- }
-
- /**
- * Holds if `iteratorAddress` is an address of an iterator that is used for
- * a read operation. The `memory` instruction represents the memory that
- * the IR's SSA analysis determined was read by the call to `operator*`.
- *
- * Finally, the `numberOfLoads` integer represents the number of dereferences
- * this read corresponds to on the underlying container that produced the iterator.
- */
- private predicate isChiBeforeIteratorUse(
- Operand iteratorAddress, Instruction memory, int numberOfLoads
- ) {
- exists(
- BaseSourceVariableInstruction iteratorBase, LoadInstruction load,
- ReadSideEffectInstruction read, Operand iteratorDerefAddress
- |
- numberOfLoads >= 0 and
- isUse(_, iteratorAddress, iteratorBase, numberOfLoads + 1, 0) and
- isUse(_, iteratorDerefAddress, iteratorBase, numberOfLoads + 2, 0) and
- iteratorBase.getResultType() instanceof Interfaces::Iterator and
- load.getSourceAddressOperand() = iteratorDerefAddress and
- read.getPrimaryInstruction() = load.getSourceAddress() and
- memory = read.getSideEffectOperand().getAnyDef()
- )
- }
-
- /**
- * Holds if `iteratorDerefAddress` is an address of an iterator dereference (i.e., `*it`)
- * that is used for a write operation that writes the value `value` to a container that
- * created the iterator. `container` represents the base of the address of the container
- * that was used to create the iterator.
- */
- cached
- predicate isIteratorDef(
- BaseSourceVariableInstruction container, Operand iteratorDerefAddress, Node0Impl value,
- int numberOfLoads, int indirectionIndex
- ) {
- exists(Instruction memory, Instruction begin, int upper, int ind |
- isChiAfterIteratorDef(memory, iteratorDerefAddress, value, numberOfLoads) and
- memorySucc*(begin, memory) and
- isChiAfterBegin(container, begin) and
- upper = countIndirectionsForCppType(getResultLanguageType(container)) and
- ind = numberOfLoads + [1 .. upper] and
- indirectionIndex = ind - (numberOfLoads + 1)
- )
- }
-
- /**
- * Holds if `iteratorAddress` is an address of an iterator that is used for a
- * read operation to read a value from a container that created the iterator.
- * `container` represents the base of the address of the container that was used
- * to create the iterator.
- */
- cached
- predicate isIteratorUse(
- BaseSourceVariableInstruction container, Operand iteratorAddress, int numberOfLoads,
- int indirectionIndex
- ) {
- // Direct use
- exists(Instruction begin, Instruction memory, int upper, int ind |
- isChiBeforeIteratorUse(iteratorAddress, memory, numberOfLoads) and
- memorySucc*(begin, memory) and
- isChiAfterBegin(container, begin) and
- upper = countIndirectionsForCppType(getResultLanguageType(container)) and
- ind = numberOfLoads + [1 .. upper] and
- indirectionIndex = ind - (numberOfLoads + 1)
- )
- or
- // Use through function output
- exists(Instruction memory, Instruction begin, int upper, int ind |
- isChiAfterIteratorArgument(memory, iteratorAddress, numberOfLoads) and
- memorySucc*(begin, memory) and
- isChiAfterBegin(container, begin) and
- upper = countIndirectionsForCppType(getResultLanguageType(container)) and
- ind = numberOfLoads + [1 .. upper] and
- indirectionIndex = ind - (numberOfLoads - 1)
- )
- }
-
/** Holds if `op` is the only use of its defining instruction, and that op is used in a conversation */
private predicate isConversion(Operand op) {
exists(Instruction def, Operand use |
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll
index b31c7898ba72..24135820ab8b 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll
@@ -17,18 +17,11 @@ private import Imports::IRType
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
* by the AST-to-IR translation (`IRTempVariable`).
*/
-class IRVariable extends TIRVariable {
+abstract private class AbstractIRVariable extends TIRVariable {
Language::Declaration func;
- IRVariable() {
- this = TIRUserVariable(_, _, func) or
- this = TIRTempVariable(func, _, _, _) or
- this = TIRStringLiteral(func, _, _, _) or
- this = TIRDynamicInitializationFlag(func, _, _)
- }
-
/** Gets a textual representation of this element. */
- string toString() { none() }
+ abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
/**
* Gets the type of the variable.
*/
- Language::LanguageType getLanguageType() { none() }
+ abstract Language::LanguageType getLanguageType();
/**
* Gets the AST node that declared this variable, or that introduced this
* variable as part of the AST-to-IR translation.
*/
- Language::AST getAst() { none() }
+ abstract Language::AST getAst();
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
* Gets an identifier string for the variable. This identifier is unique
* within the function.
*/
- string getUniqueId() { none() }
+ abstract string getUniqueId();
/**
* Gets the source location of this variable.
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the IR for the function that references this variable.
*/
- final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
+ final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
/**
* Gets the function that references this variable.
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
final Language::Declaration getEnclosingFunction() { result = func }
}
+/**
+ * A variable referenced by the IR for a function.
+ *
+ * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
+ * by the AST-to-IR translation (`IRTempVariable`).
+ */
+final class IRVariable = AbstractIRVariable;
+
/**
* A user-declared variable referenced by the IR for a function.
*/
-class IRUserVariable extends IRVariable, TIRUserVariable {
+class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
Language::Variable var;
Language::LanguageType type;
@@ -114,27 +115,30 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
* parameters, non-static local variables, and temporary variables.
*/
-class IRAutomaticVariable extends IRVariable {
- IRAutomaticVariable() {
- exists(Language::Variable var |
- this = TIRUserVariable(var, _, func) and
- Language::isVariableAutomatic(var)
- )
- or
- this = TIRTempVariable(func, _, _, _)
- }
-}
+abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
+
+/**
+ * A variable (user-declared or temporary) that is allocated on the stack. This includes all
+ * parameters, non-static local variables, and temporary variables.
+ */
+final class IRAutomaticVariable = AbstractIRAutomaticVariable;
/**
* A user-declared variable that is allocated on the stack. This includes all parameters and
* non-static local variables.
*/
-class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
+private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
override Language::AutomaticVariable var;
final override Language::AutomaticVariable getVariable() { result = var }
}
+/**
+ * A user-declared variable that is allocated on the stack. This includes all parameters and
+ * non-static local variables.
+ */
+final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
+
/**
* A user-declared variable that is not allocated on the stack. This includes all global variables,
* namespace-scope variables, static fields, and static local variables.
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
* A variable that is not user-declared. This includes temporary variables generated as part of IR
* construction, as well as string literals.
*/
-class IRGeneratedVariable extends IRVariable {
+abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
Language::AST ast;
Language::LanguageType type;
- IRGeneratedVariable() {
- this = TIRTempVariable(func, ast, _, type) or
- this = TIRStringLiteral(func, ast, type, _) or
- this = TIRDynamicInitializationFlag(func, ast, type)
- }
-
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAst() { result = ast }
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
string getBaseString() { none() }
}
+/**
+ * A variable that is not user-declared. This includes temporary variables generated as part of IR
+ * construction, as well as string literals.
+ */
+final class IRGeneratedVariable = AbstractIRGeneratedVariable;
+
/**
* A temporary variable introduced by IR construction. The most common examples are the variable
* generated to hold the return value of a function, or the variable generated to hold the result of
* a condition operator (`a ? b : c`).
*/
-class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
+class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
+ TIRTempVariable
+{
TempVariableTag tag;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
* function that accepts a variable number of arguments.
*/
-class IREllipsisVariable extends IRTempVariable, IRParameter {
+class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
IREllipsisVariable() { tag = EllipsisTempVar() }
final override string toString() { result = "#ellipsis" }
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
/**
* A temporary variable generated to hold the `this` pointer.
*/
-class IRThisVariable extends IRTempVariable, IRParameter {
+class IRThisVariable extends IRTempVariable, AbstractIRParameter {
IRThisVariable() { tag = ThisTempVar() }
final override string toString() { result = "#this" }
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
* A variable generated to represent the contents of a string literal. This variable acts much like
* a read-only global variable.
*/
-class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
+class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
* used to model the runtime initialization of static local variables in C++, as well as static
* fields in C#.
*/
-class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
+class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
Language::Variable var;
IRDynamicInitializationFlag() {
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
* An IR variable which acts like a function parameter, including positional parameters and the
* temporary variables generated for `this` and ellipsis parameters.
*/
-class IRParameter extends IRAutomaticVariable {
- IRParameter() {
- this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
- or
- this = TIRTempVariable(_, _, ThisTempVar(), _)
- or
- this = TIRTempVariable(_, _, EllipsisTempVar(), _)
- }
-
+abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
/**
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
*/
int getIndex() { none() }
}
+/**
+ * An IR variable which acts like a function parameter, including positional parameters and the
+ * temporary variables generated for `this` and ellipsis parameters.
+ */
+final class IRParameter = AbstractIRParameter;
+
/**
* An IR variable representing a positional parameter.
*/
-class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
+class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
+ IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
+
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
index 189ffce2903e..c7e40da1e17c 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
@@ -247,8 +247,7 @@ class Instruction extends Construction::TStageInstruction {
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
- cached
- final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() }
+ final IRType getResultIRType() { result = Construction::getInstructionResultIRType(this) }
/**
* Gets the type of the result produced by this instruction. If the
@@ -995,9 +994,8 @@ class ConstantInstruction extends ConstantValueInstruction {
*/
class IntegerConstantInstruction extends ConstantInstruction {
IntegerConstantInstruction() {
- exists(IRType resultType |
- resultType = this.getResultIRType() and
- (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
+ exists(IRType resultType | resultType = this.getResultIRType() |
+ resultType instanceof IRIntegerType or resultType instanceof IRBooleanType
)
}
}
@@ -1009,6 +1007,17 @@ class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType }
}
+/**
+ * An instruction whose result is a constant value of a pointer type.
+ */
+class PointerConstantInstruction extends ConstantInstruction {
+ PointerConstantInstruction() {
+ exists(IRType resultType | resultType = this.getResultIRType() |
+ resultType instanceof IRAddressType or resultType instanceof IRFunctionAddressType
+ )
+ }
+}
+
/**
* An instruction whose result is the address of a string literal.
*/
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll
index 209c42726b7d..d2e68c733041 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll
@@ -429,6 +429,11 @@ private module Cached {
instr = unreachedInstruction(_) and result = Language::getVoidType()
}
+ cached
+ IRType getInstructionResultIRType(Instruction instr) {
+ result = instr.getResultLanguageType().getIRType()
+ }
+
/**
* Holds if `opcode` is the opcode that specifies the operation performed by `instr`.
*
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRVariable.qll
index b31c7898ba72..24135820ab8b 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRVariable.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRVariable.qll
@@ -17,18 +17,11 @@ private import Imports::IRType
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
* by the AST-to-IR translation (`IRTempVariable`).
*/
-class IRVariable extends TIRVariable {
+abstract private class AbstractIRVariable extends TIRVariable {
Language::Declaration func;
- IRVariable() {
- this = TIRUserVariable(_, _, func) or
- this = TIRTempVariable(func, _, _, _) or
- this = TIRStringLiteral(func, _, _, _) or
- this = TIRDynamicInitializationFlag(func, _, _)
- }
-
/** Gets a textual representation of this element. */
- string toString() { none() }
+ abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
/**
* Gets the type of the variable.
*/
- Language::LanguageType getLanguageType() { none() }
+ abstract Language::LanguageType getLanguageType();
/**
* Gets the AST node that declared this variable, or that introduced this
* variable as part of the AST-to-IR translation.
*/
- Language::AST getAst() { none() }
+ abstract Language::AST getAst();
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
* Gets an identifier string for the variable. This identifier is unique
* within the function.
*/
- string getUniqueId() { none() }
+ abstract string getUniqueId();
/**
* Gets the source location of this variable.
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the IR for the function that references this variable.
*/
- final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
+ final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
/**
* Gets the function that references this variable.
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
final Language::Declaration getEnclosingFunction() { result = func }
}
+/**
+ * A variable referenced by the IR for a function.
+ *
+ * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
+ * by the AST-to-IR translation (`IRTempVariable`).
+ */
+final class IRVariable = AbstractIRVariable;
+
/**
* A user-declared variable referenced by the IR for a function.
*/
-class IRUserVariable extends IRVariable, TIRUserVariable {
+class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
Language::Variable var;
Language::LanguageType type;
@@ -114,27 +115,30 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
* parameters, non-static local variables, and temporary variables.
*/
-class IRAutomaticVariable extends IRVariable {
- IRAutomaticVariable() {
- exists(Language::Variable var |
- this = TIRUserVariable(var, _, func) and
- Language::isVariableAutomatic(var)
- )
- or
- this = TIRTempVariable(func, _, _, _)
- }
-}
+abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
+
+/**
+ * A variable (user-declared or temporary) that is allocated on the stack. This includes all
+ * parameters, non-static local variables, and temporary variables.
+ */
+final class IRAutomaticVariable = AbstractIRAutomaticVariable;
/**
* A user-declared variable that is allocated on the stack. This includes all parameters and
* non-static local variables.
*/
-class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
+private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
override Language::AutomaticVariable var;
final override Language::AutomaticVariable getVariable() { result = var }
}
+/**
+ * A user-declared variable that is allocated on the stack. This includes all parameters and
+ * non-static local variables.
+ */
+final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
+
/**
* A user-declared variable that is not allocated on the stack. This includes all global variables,
* namespace-scope variables, static fields, and static local variables.
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
* A variable that is not user-declared. This includes temporary variables generated as part of IR
* construction, as well as string literals.
*/
-class IRGeneratedVariable extends IRVariable {
+abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
Language::AST ast;
Language::LanguageType type;
- IRGeneratedVariable() {
- this = TIRTempVariable(func, ast, _, type) or
- this = TIRStringLiteral(func, ast, type, _) or
- this = TIRDynamicInitializationFlag(func, ast, type)
- }
-
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAst() { result = ast }
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
string getBaseString() { none() }
}
+/**
+ * A variable that is not user-declared. This includes temporary variables generated as part of IR
+ * construction, as well as string literals.
+ */
+final class IRGeneratedVariable = AbstractIRGeneratedVariable;
+
/**
* A temporary variable introduced by IR construction. The most common examples are the variable
* generated to hold the return value of a function, or the variable generated to hold the result of
* a condition operator (`a ? b : c`).
*/
-class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
+class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
+ TIRTempVariable
+{
TempVariableTag tag;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
* function that accepts a variable number of arguments.
*/
-class IREllipsisVariable extends IRTempVariable, IRParameter {
+class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
IREllipsisVariable() { tag = EllipsisTempVar() }
final override string toString() { result = "#ellipsis" }
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
/**
* A temporary variable generated to hold the `this` pointer.
*/
-class IRThisVariable extends IRTempVariable, IRParameter {
+class IRThisVariable extends IRTempVariable, AbstractIRParameter {
IRThisVariable() { tag = ThisTempVar() }
final override string toString() { result = "#this" }
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
* A variable generated to represent the contents of a string literal. This variable acts much like
* a read-only global variable.
*/
-class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
+class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
* used to model the runtime initialization of static local variables in C++, as well as static
* fields in C#.
*/
-class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
+class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
Language::Variable var;
IRDynamicInitializationFlag() {
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
* An IR variable which acts like a function parameter, including positional parameters and the
* temporary variables generated for `this` and ellipsis parameters.
*/
-class IRParameter extends IRAutomaticVariable {
- IRParameter() {
- this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
- or
- this = TIRTempVariable(_, _, ThisTempVar(), _)
- or
- this = TIRTempVariable(_, _, EllipsisTempVar(), _)
- }
-
+abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
/**
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
*/
int getIndex() { none() }
}
+/**
+ * An IR variable which acts like a function parameter, including positional parameters and the
+ * temporary variables generated for `this` and ellipsis parameters.
+ */
+final class IRParameter = AbstractIRParameter;
+
/**
* An IR variable representing a positional parameter.
*/
-class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
+class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
+ IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
+
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll
index 189ffce2903e..c7e40da1e17c 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll
@@ -247,8 +247,7 @@ class Instruction extends Construction::TStageInstruction {
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
- cached
- final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() }
+ final IRType getResultIRType() { result = Construction::getInstructionResultIRType(this) }
/**
* Gets the type of the result produced by this instruction. If the
@@ -995,9 +994,8 @@ class ConstantInstruction extends ConstantValueInstruction {
*/
class IntegerConstantInstruction extends ConstantInstruction {
IntegerConstantInstruction() {
- exists(IRType resultType |
- resultType = this.getResultIRType() and
- (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
+ exists(IRType resultType | resultType = this.getResultIRType() |
+ resultType instanceof IRIntegerType or resultType instanceof IRBooleanType
)
}
}
@@ -1009,6 +1007,17 @@ class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType }
}
+/**
+ * An instruction whose result is a constant value of a pointer type.
+ */
+class PointerConstantInstruction extends ConstantInstruction {
+ PointerConstantInstruction() {
+ exists(IRType resultType | resultType = this.getResultIRType() |
+ resultType instanceof IRAddressType or resultType instanceof IRFunctionAddressType
+ )
+ }
+}
+
/**
* An instruction whose result is the address of a string literal.
*/
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll
index 96a01954d17f..7bea8178d141 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll
@@ -377,6 +377,10 @@ CppType getInstructionResultType(TStageInstruction instr) {
result = getVoidType()
}
+IRType getInstructionResultIRType(Instruction instr) {
+ result = instr.getResultLanguageType().getIRType()
+}
+
predicate getInstructionOpcode(Opcode opcode, TStageInstruction instr) {
getInstructionTranslatedElement(instr).hasInstruction(opcode, getInstructionTag(instr), _)
or
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll
index 3f4039ebb346..a43595b08e08 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll
@@ -538,6 +538,11 @@ class TranslatedResultCopy extends TranslatedExpr, TTranslatedResultCopy {
final override predicate producesExprResult() { any() }
private TranslatedCoreExpr getOperand() { result.getExpr() = expr }
+
+ override predicate handlesDestructorsExplicitly() {
+ // The destructor calls will already have been generated by the translation of `expr`.
+ any()
+ }
}
class TranslatedCommaExpr extends TranslatedNonConstantExpr {
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll
index fab2dacc8a78..3f77a2b0b45e 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll
@@ -1163,6 +1163,8 @@ class TranslatedForStmt extends TranslatedLoop {
class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
override RangeBasedForStmt stmt;
+ override predicate handlesDestructorsExplicitly() { any() }
+
override TranslatedElement getChildInternal(int id) {
id = 0 and result = this.getInitialization()
or
@@ -1216,6 +1218,19 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
or
child = this.getUpdate() and
result = this.getCondition().getFirstInstruction(kind)
+ or
+ exists(int destructorId |
+ destructorId >= this.getFirstDestructorCallIndex() and
+ child = this.getChild(destructorId) and
+ result = this.getChild(destructorId + 1).getFirstInstruction(kind)
+ )
+ or
+ exists(int lastDestructorIndex |
+ lastDestructorIndex =
+ max(int n | exists(this.getChild(n)) and n >= this.getFirstDestructorCallIndex()) and
+ child = this.getChild(lastDestructorIndex) and
+ result = this.getParent().getChildSuccessor(this, kind)
+ )
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -1231,7 +1246,9 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getCondition() and
- result = this.getParent().getChildSuccessor(this, kind)
+ if this.hasAnImplicitDestructorCall()
+ then result = this.getChild(this.getFirstDestructorCallIndex()).getFirstInstruction(kind)
+ else result = this.getParent().getChildSuccessor(this, kind)
}
private TranslatedDeclStmt getRangeVariableDeclStmt() {
@@ -1276,6 +1293,11 @@ class TranslatedJumpStmt extends TranslatedStmt {
override JumpStmt stmt;
override Instruction getFirstInstruction(EdgeKind kind) {
+ // The first instruction is a destructor call, if any.
+ result = this.getChildInternal(0).getFirstInstruction(kind)
+ or
+ // Otherwise, the first (and only) instruction is a `NoOp`
+ not exists(this.getChildInternal(0)) and
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
@@ -1284,7 +1306,20 @@ class TranslatedJumpStmt extends TranslatedStmt {
result = this.getInstruction(OnlyInstructionTag())
}
- override TranslatedElement getChildInternal(int id) { none() }
+ private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
+ result.getExpr() = stmt.getImplicitDestructorCall(id)
+ }
+
+ override TranslatedElement getLastChild() {
+ result =
+ this.getTranslatedImplicitDestructorCall(max(int id |
+ exists(stmt.getImplicitDestructorCall(id))
+ ))
+ }
+
+ override TranslatedElement getChildInternal(int id) {
+ result = this.getTranslatedImplicitDestructorCall(id)
+ }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = OnlyInstructionTag() and
@@ -1297,7 +1332,19 @@ class TranslatedJumpStmt extends TranslatedStmt {
result = getTranslatedStmt(stmt.getTarget()).getFirstInstruction(kind)
}
- override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { none() }
+ final override predicate handlesDestructorsExplicitly() { any() }
+
+ override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
+ exists(int id | child = this.getChildInternal(id) |
+ // Transition to the next destructor call, if any.
+ result = this.getChildInternal(id + 1).getFirstInstruction(kind)
+ or
+ // And otherwise, exit this element by flowing to the target of the jump.
+ not exists(this.getChildInternal(id + 1)) and
+ kind instanceof GotoEdge and
+ result = this.getInstruction(OnlyInstructionTag())
+ )
+ }
}
private EdgeKind getCaseEdge(SwitchCase switchCase) {
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll
index b31c7898ba72..24135820ab8b 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll
@@ -17,18 +17,11 @@ private import Imports::IRType
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
* by the AST-to-IR translation (`IRTempVariable`).
*/
-class IRVariable extends TIRVariable {
+abstract private class AbstractIRVariable extends TIRVariable {
Language::Declaration func;
- IRVariable() {
- this = TIRUserVariable(_, _, func) or
- this = TIRTempVariable(func, _, _, _) or
- this = TIRStringLiteral(func, _, _, _) or
- this = TIRDynamicInitializationFlag(func, _, _)
- }
-
/** Gets a textual representation of this element. */
- string toString() { none() }
+ abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
/**
* Gets the type of the variable.
*/
- Language::LanguageType getLanguageType() { none() }
+ abstract Language::LanguageType getLanguageType();
/**
* Gets the AST node that declared this variable, or that introduced this
* variable as part of the AST-to-IR translation.
*/
- Language::AST getAst() { none() }
+ abstract Language::AST getAst();
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
* Gets an identifier string for the variable. This identifier is unique
* within the function.
*/
- string getUniqueId() { none() }
+ abstract string getUniqueId();
/**
* Gets the source location of this variable.
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the IR for the function that references this variable.
*/
- final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
+ final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
/**
* Gets the function that references this variable.
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
final Language::Declaration getEnclosingFunction() { result = func }
}
+/**
+ * A variable referenced by the IR for a function.
+ *
+ * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
+ * by the AST-to-IR translation (`IRTempVariable`).
+ */
+final class IRVariable = AbstractIRVariable;
+
/**
* A user-declared variable referenced by the IR for a function.
*/
-class IRUserVariable extends IRVariable, TIRUserVariable {
+class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
Language::Variable var;
Language::LanguageType type;
@@ -114,27 +115,30 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
* parameters, non-static local variables, and temporary variables.
*/
-class IRAutomaticVariable extends IRVariable {
- IRAutomaticVariable() {
- exists(Language::Variable var |
- this = TIRUserVariable(var, _, func) and
- Language::isVariableAutomatic(var)
- )
- or
- this = TIRTempVariable(func, _, _, _)
- }
-}
+abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
+
+/**
+ * A variable (user-declared or temporary) that is allocated on the stack. This includes all
+ * parameters, non-static local variables, and temporary variables.
+ */
+final class IRAutomaticVariable = AbstractIRAutomaticVariable;
/**
* A user-declared variable that is allocated on the stack. This includes all parameters and
* non-static local variables.
*/
-class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
+private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
override Language::AutomaticVariable var;
final override Language::AutomaticVariable getVariable() { result = var }
}
+/**
+ * A user-declared variable that is allocated on the stack. This includes all parameters and
+ * non-static local variables.
+ */
+final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
+
/**
* A user-declared variable that is not allocated on the stack. This includes all global variables,
* namespace-scope variables, static fields, and static local variables.
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
* A variable that is not user-declared. This includes temporary variables generated as part of IR
* construction, as well as string literals.
*/
-class IRGeneratedVariable extends IRVariable {
+abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
Language::AST ast;
Language::LanguageType type;
- IRGeneratedVariable() {
- this = TIRTempVariable(func, ast, _, type) or
- this = TIRStringLiteral(func, ast, type, _) or
- this = TIRDynamicInitializationFlag(func, ast, type)
- }
-
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAst() { result = ast }
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
string getBaseString() { none() }
}
+/**
+ * A variable that is not user-declared. This includes temporary variables generated as part of IR
+ * construction, as well as string literals.
+ */
+final class IRGeneratedVariable = AbstractIRGeneratedVariable;
+
/**
* A temporary variable introduced by IR construction. The most common examples are the variable
* generated to hold the return value of a function, or the variable generated to hold the result of
* a condition operator (`a ? b : c`).
*/
-class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
+class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
+ TIRTempVariable
+{
TempVariableTag tag;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
* function that accepts a variable number of arguments.
*/
-class IREllipsisVariable extends IRTempVariable, IRParameter {
+class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
IREllipsisVariable() { tag = EllipsisTempVar() }
final override string toString() { result = "#ellipsis" }
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
/**
* A temporary variable generated to hold the `this` pointer.
*/
-class IRThisVariable extends IRTempVariable, IRParameter {
+class IRThisVariable extends IRTempVariable, AbstractIRParameter {
IRThisVariable() { tag = ThisTempVar() }
final override string toString() { result = "#this" }
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
* A variable generated to represent the contents of a string literal. This variable acts much like
* a read-only global variable.
*/
-class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
+class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
* used to model the runtime initialization of static local variables in C++, as well as static
* fields in C#.
*/
-class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
+class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
Language::Variable var;
IRDynamicInitializationFlag() {
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
* An IR variable which acts like a function parameter, including positional parameters and the
* temporary variables generated for `this` and ellipsis parameters.
*/
-class IRParameter extends IRAutomaticVariable {
- IRParameter() {
- this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
- or
- this = TIRTempVariable(_, _, ThisTempVar(), _)
- or
- this = TIRTempVariable(_, _, EllipsisTempVar(), _)
- }
-
+abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
/**
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
*/
int getIndex() { none() }
}
+/**
+ * An IR variable which acts like a function parameter, including positional parameters and the
+ * temporary variables generated for `this` and ellipsis parameters.
+ */
+final class IRParameter = AbstractIRParameter;
+
/**
* An IR variable representing a positional parameter.
*/
-class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
+class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
+ IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
+
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
index 189ffce2903e..c7e40da1e17c 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
@@ -247,8 +247,7 @@ class Instruction extends Construction::TStageInstruction {
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
- cached
- final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() }
+ final IRType getResultIRType() { result = Construction::getInstructionResultIRType(this) }
/**
* Gets the type of the result produced by this instruction. If the
@@ -995,9 +994,8 @@ class ConstantInstruction extends ConstantValueInstruction {
*/
class IntegerConstantInstruction extends ConstantInstruction {
IntegerConstantInstruction() {
- exists(IRType resultType |
- resultType = this.getResultIRType() and
- (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
+ exists(IRType resultType | resultType = this.getResultIRType() |
+ resultType instanceof IRIntegerType or resultType instanceof IRBooleanType
)
}
}
@@ -1009,6 +1007,17 @@ class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType }
}
+/**
+ * An instruction whose result is a constant value of a pointer type.
+ */
+class PointerConstantInstruction extends ConstantInstruction {
+ PointerConstantInstruction() {
+ exists(IRType resultType | resultType = this.getResultIRType() |
+ resultType instanceof IRAddressType or resultType instanceof IRFunctionAddressType
+ )
+ }
+}
+
/**
* An instruction whose result is the address of a string literal.
*/
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll
index 209c42726b7d..d2e68c733041 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll
@@ -429,6 +429,11 @@ private module Cached {
instr = unreachedInstruction(_) and result = Language::getVoidType()
}
+ cached
+ IRType getInstructionResultIRType(Instruction instr) {
+ result = instr.getResultLanguageType().getIRType()
+ }
+
/**
* Holds if `opcode` is the opcode that specifies the operation performed by `instr`.
*
diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Iterator.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Iterator.qll
index 8e527c7e6947..a016210de5a0 100644
--- a/cpp/ql/lib/semmle/code/cpp/models/implementations/Iterator.qll
+++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Iterator.qll
@@ -560,7 +560,7 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
TaintFunction, SideEffectFunction, AliasFunction
{
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
- input.isParameterDeref(0) and
+ (input.isParameterDeref(0) or input.isParameter(0)) and
output.isQualifierObject()
}
@@ -579,17 +579,34 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
}
+/**
+ * A `begin` member function, or a related function, that returns an iterator.
+ */
+class BeginFunction extends MemberFunction {
+ BeginFunction() {
+ this.hasName(["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]) and
+ this.getType().getUnspecifiedType() instanceof Iterator
+ }
+}
+
+/**
+ * An `end` member function, or a related function, that returns an iterator.
+ */
+class EndFunction extends MemberFunction {
+ EndFunction() {
+ this.hasName(["end", "cend", "rend", "crend"]) and
+ this.getType().getUnspecifiedType() instanceof Iterator
+ }
+}
+
/**
* A `begin` or `end` member function, or a related member function, that
* returns an iterator.
*/
class BeginOrEndFunction extends MemberFunction {
BeginOrEndFunction() {
- this.hasName([
- "begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend", "before_begin",
- "cbefore_begin"
- ]) and
- this.getType().getUnspecifiedType() instanceof Iterator
+ this instanceof BeginFunction or
+ this instanceof EndFunction
}
}
diff --git a/cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll b/cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll
deleted file mode 100644
index 8f43e19c7b55..000000000000
--- a/cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll
+++ /dev/null
@@ -1,616 +0,0 @@
-/**
- * DEPRECATED: This library has been replaced with a newer version which
- * provides better performance and precision. Use
- * `semmle.code.cpp.valuenumbering.GlobalValueNumbering` instead.
- *
- * Provides an implementation of Global Value Numbering.
- * See https://en.wikipedia.org/wiki/Global_value_numbering
- *
- * The predicate `globalValueNumber` converts an expression into a `GVN`,
- * which is an abstract type representing the value of the expression. If
- * two expressions have the same `GVN` then they compute the same value.
- * For example:
- *
- * ```
- * void f(int x, int y) {
- * g(x+y, x+y);
- * }
- * ```
- *
- * In this example, both arguments in the call to `g` compute the same value,
- * so both arguments have the same `GVN`. In other words, we can find
- * this call with the following query:
- *
- * ```
- * from FunctionCall call, GVN v
- * where v = globalValueNumber(call.getArgument(0))
- * and v = globalValueNumber(call.getArgument(1))
- * select call
- * ```
- *
- * The analysis is conservative, so two expressions might have different
- * `GVN`s even though the actually always compute the same value. The most
- * common reason for this is that the analysis cannot prove that there
- * are no side-effects that might cause the computed value to change.
- */
-
-/*
- * Note to developers: the correctness of this module depends on the
- * definitions of GVN, globalValueNumber, and analyzableExpr being kept in
- * sync with each other. If you change this module then make sure that the
- * change is symmetric across all three.
- */
-
-import cpp
-private import semmle.code.cpp.controlflow.SSA
-
-/**
- * Holds if the result is a control flow node that might change the
- * value of any global variable. This is used in the implementation
- * of `GVN_OtherVariable`, because we need to be quite conservative when
- * we assign a value number to a global variable. For example:
- *
- * ```
- * x = g+1;
- * dosomething();
- * y = g+1;
- * ```
- *
- * It is not safe to assign the same value number to both instances
- * of `g+1` in this example, because the call to `dosomething` might
- * change the value of `g`.
- */
-private ControlFlowNode nodeWithPossibleSideEffect() {
- result instanceof Call
- or
- // If the lhs of an assignment is not analyzable by SSA, then
- // we need to treat the assignment as having a possible side-effect.
- result instanceof Assignment and not result instanceof SsaDefinition
- or
- result instanceof CrementOperation and not result instanceof SsaDefinition
- or
- exists(LocalVariable v |
- result = v.getInitializer().getExpr() and not result instanceof SsaDefinition
- )
- or
- result instanceof AsmStmt
-}
-
-/**
- * Gets the entry node of the control flow graph of which `node` is a
- * member.
- */
-cached
-private ControlFlowNode getControlFlowEntry(ControlFlowNode node) {
- result = node.getControlFlowScope().getEntryPoint() and
- result.getASuccessor*() = node
-}
-
-/**
- * Holds if there is a control flow edge from `src` to `dst` or
- * if `dst` is an expression with a possible side-effect. The idea
- * is to treat side effects as entry points in the control flow
- * graph so that we can use the dominator tree to find the most recent
- * side-effect.
- */
-private predicate sideEffectCfg(ControlFlowNode src, ControlFlowNode dst) {
- src.getASuccessor() = dst
- or
- // Add an edge from the entry point to any node that might have a side
- // effect.
- dst = nodeWithPossibleSideEffect() and
- src = getControlFlowEntry(dst)
-}
-
-/**
- * Holds if `dominator` is the immediate dominator of `node` in
- * the side-effect CFG.
- */
-private predicate iDomEffect(ControlFlowNode dominator, ControlFlowNode node) =
- idominance(functionEntry/1, sideEffectCfg/2)(_, dominator, node)
-
-/**
- * Gets the most recent side effect. To be more precise, `result` is a
- * dominator of `node` and no side-effects can occur between `result` and
- * `node`.
- *
- * `sideEffectCFG` has an edge from the function entry to every node with a
- * side-effect. This means that every node with a side-effect has the
- * function entry as its immediate dominator. So if node `x` dominates node
- * `y` then there can be no side effects between `x` and `y` unless `x` is
- * the function entry. So the optimal choice for `result` has the function
- * entry as its immediate dominator.
- *
- * Example:
- *
- * ```
- * 000: int f(int a, int b, int *p) {
- * 001: int r = 0;
- * 002: if (a) {
- * 003: if (b) {
- * 004: sideEffect1();
- * 005: }
- * 006: } else {
- * 007: sideEffect2();
- * 008: }
- * 009: if (a) {
- * 010: r++; // Not a side-effect, because r is an SSA variable.
- * 011: }
- * 012: if (b) {
- * 013: r++; // Not a side-effect, because r is an SSA variable.
- * 014: }
- * 015: return *p;
- * 016: }
- * ```
- *
- * Suppose we want to find the most recent side-effect for the dereference
- * of `p` on line 015. The `sideEffectCFG` has an edge from the function
- * entry (line 000) to the side effects at lines 004 and 007. Therefore,
- * the immediate dominator tree looks like this:
- *
- * 000 - 001 - 002 - 003
- * - 004
- * - 007
- * - 009 - 010
- * - 012 - 013
- * - 015
- *
- * The immediate dominator path to line 015 is 000 - 009 - 012 - 015.
- * Therefore, the most recent side effect for line 015 is line 009.
- */
-cached
-private ControlFlowNode mostRecentSideEffect(ControlFlowNode node) {
- exists(ControlFlowNode entry |
- functionEntry(entry) and
- iDomEffect(entry, result) and
- iDomEffect*(result, node)
- )
-}
-
-/** Used to represent the "global value number" of an expression. */
-cached
-private newtype GvnBase =
- GVN_IntConst(int val, Type t) { mk_IntConst(val, t, _) } or
- GVN_FloatConst(float val, Type t) { mk_FloatConst(val, t, _) } or
- // If the local variable does not have a defining value, then
- // we use the SsaDefinition as its global value number.
- GVN_UndefinedStackVariable(StackVariable x, SsaDefinition def) {
- mk_UndefinedStackVariable(x, def, _)
- } or
- // Variables with no SSA information. As a crude (but safe)
- // approximation, we use `mostRecentSideEffect` to compute a definition
- // location for the variable. This ensures that two instances of the same
- // global variable will only get the same value number if they are
- // guaranteed to have the same value.
- GVN_OtherVariable(Variable x, ControlFlowNode dominator) { mk_OtherVariable(x, dominator, _) } or
- deprecated GVN_FieldAccess(GVN s, Field f) {
- mk_DotFieldAccess(s, f, _) or
- mk_PointerFieldAccess_with_deref(s, f, _) or
- mk_ImplicitThisFieldAccess_with_deref(s, f, _)
- } or
- // Dereference a pointer. The value might have changed since the last
- // time the pointer was dereferenced, so we need to include a definition
- // location. As a crude (but safe) approximation, we use
- // `mostRecentSideEffect` to compute a definition location.
- deprecated GVN_Deref(GVN p, ControlFlowNode dominator) {
- mk_Deref(p, dominator, _) or
- mk_PointerFieldAccess(p, _, dominator, _) or
- mk_ImplicitThisFieldAccess_with_qualifier(p, _, dominator, _)
- } or
- GVN_ThisExpr(Function fcn) {
- mk_ThisExpr(fcn, _) or
- mk_ImplicitThisFieldAccess(fcn, _, _, _)
- } or
- deprecated GVN_Conversion(Type t, GVN child) { mk_Conversion(t, child, _) } or
- deprecated GVN_BinaryOp(GVN lhs, GVN rhs, string opname) { mk_BinaryOp(lhs, rhs, opname, _) } or
- deprecated GVN_UnaryOp(GVN child, string opname) { mk_UnaryOp(child, opname, _) } or
- deprecated GVN_ArrayAccess(GVN x, GVN i, ControlFlowNode dominator) {
- mk_ArrayAccess(x, i, dominator, _)
- } or
- // Any expression that is not handled by the cases above is
- // given a unique number based on the expression itself.
- GVN_Unanalyzable(Expr e) { not analyzableExpr(e) }
-
-/**
- * A Global Value Number. A GVN is an abstract representation of the value
- * computed by an expression. The relationship between `Expr` and `GVN` is
- * many-to-one: every `Expr` has exactly one `GVN`, but multiple
- * expressions can have the same `GVN`. If two expressions have the same
- * `GVN`, it means that they compute the same value at run time. The `GVN`
- * is an opaque value, so you cannot deduce what the run-time value of an
- * expression will be from its `GVN`. The only use for the `GVN` of an
- * expression is to find other expressions that compute the same value.
- * Use the predicate `globalValueNumber` to get the `GVN` for an `Expr`.
- *
- * Note: `GVN` has `toString` and `getLocation` methods, so that it can be
- * displayed in a results list. These work by picking an arbitrary
- * expression with this `GVN` and using its `toString` and `getLocation`
- * methods.
- */
-deprecated class GVN extends GvnBase {
- GVN() { this instanceof GvnBase }
-
- /** Gets an expression that has this GVN. */
- Expr getAnExpr() { this = globalValueNumber(result) }
-
- /** Gets the kind of the GVN. This can be useful for debugging. */
- string getKind() {
- if this instanceof GVN_IntConst
- then result = "IntConst"
- else
- if this instanceof GVN_FloatConst
- then result = "FloatConst"
- else
- if this instanceof GVN_UndefinedStackVariable
- then result = "UndefinedStackVariable"
- else
- if this instanceof GVN_OtherVariable
- then result = "OtherVariable"
- else
- if this instanceof GVN_FieldAccess
- then result = "FieldAccess"
- else
- if this instanceof GVN_Deref
- then result = "Deref"
- else
- if this instanceof GVN_ThisExpr
- then result = "ThisExpr"
- else
- if this instanceof GVN_Conversion
- then result = "Conversion"
- else
- if this instanceof GVN_BinaryOp
- then result = "BinaryOp"
- else
- if this instanceof GVN_UnaryOp
- then result = "UnaryOp"
- else
- if this instanceof GVN_ArrayAccess
- then result = "ArrayAccess"
- else
- if this instanceof GVN_Unanalyzable
- then result = "Unanalyzable"
- else result = "error"
- }
-
- /**
- * Gets an example of an expression with this GVN.
- * This is useful for things like implementing toString().
- */
- private Expr exampleExpr() {
- // Pick the expression with the minimum source location string. This is
- // just an arbitrary way to pick an expression with this `GVN`.
- result = min(Expr e | this = globalValueNumber(e) | e order by e.getLocation().toString())
- }
-
- /** Gets a textual representation of this element. */
- string toString() { result = this.exampleExpr().toString() }
-
- /** Gets the primary location of this element. */
- Location getLocation() { result = this.exampleExpr().getLocation() }
-}
-
-private predicate analyzableIntConst(Expr e) {
- strictcount(e.getValue().toInt()) = 1 and
- strictcount(e.getUnspecifiedType()) = 1
-}
-
-private predicate mk_IntConst(int val, Type t, Expr e) {
- analyzableIntConst(e) and
- val = e.getValue().toInt() and
- t = e.getUnspecifiedType()
-}
-
-private predicate analyzableFloatConst(Expr e) {
- strictcount(e.getValue().toFloat()) = 1 and
- strictcount(e.getUnspecifiedType()) = 1 and
- not analyzableIntConst(e)
-}
-
-private predicate mk_FloatConst(float val, Type t, Expr e) {
- analyzableFloatConst(e) and
- val = e.getValue().toFloat() and
- t = e.getUnspecifiedType()
-}
-
-private predicate analyzableStackVariable(VariableAccess access) {
- strictcount(SsaDefinition def | def.getAUse(_) = access | def) = 1 and
- strictcount(SsaDefinition def, Variable v | def.getAUse(v) = access | v) = 1 and
- count(SsaDefinition def, Variable v |
- def.getAUse(v) = access
- |
- def.getDefiningValue(v).getFullyConverted()
- ) <= 1 and
- not analyzableConst(access)
-}
-
-// Note: this predicate only has a result if the access has no
-// defining value. If there is a defining value, then there is no
-// need to generate a fresh `GVN` for the access because `globalValueNumber`
-// will follow the chain and use the GVN of the defining value.
-private predicate mk_UndefinedStackVariable(
- StackVariable x, SsaDefinition def, VariableAccess access
-) {
- analyzableStackVariable(access) and
- access = def.getAUse(x) and
- not exists(def.getDefiningValue(x))
-}
-
-private predicate analyzableDotFieldAccess(DotFieldAccess access) {
- strictcount(access.getTarget()) = 1 and
- strictcount(access.getQualifier().getFullyConverted()) = 1 and
- not analyzableConst(access)
-}
-
-deprecated private predicate mk_DotFieldAccess(GVN qualifier, Field target, DotFieldAccess access) {
- analyzableDotFieldAccess(access) and
- target = access.getTarget() and
- qualifier = globalValueNumber(access.getQualifier().getFullyConverted())
-}
-
-private predicate analyzablePointerFieldAccess(PointerFieldAccess access) {
- strictcount(mostRecentSideEffect(access)) = 1 and
- strictcount(access.getTarget()) = 1 and
- strictcount(access.getQualifier().getFullyConverted()) = 1 and
- not analyzableConst(access)
-}
-
-deprecated private predicate mk_PointerFieldAccess(
- GVN qualifier, Field target, ControlFlowNode dominator, PointerFieldAccess access
-) {
- analyzablePointerFieldAccess(access) and
- dominator = mostRecentSideEffect(access) and
- target = access.getTarget() and
- qualifier = globalValueNumber(access.getQualifier().getFullyConverted())
-}
-
-/**
- * `obj->field` is equivalent to `(*obj).field`, so we need to wrap an
- * extra `GVN_Deref` around the qualifier.
- */
-deprecated private predicate mk_PointerFieldAccess_with_deref(
- GVN new_qualifier, Field target, PointerFieldAccess access
-) {
- exists(GVN qualifier, ControlFlowNode dominator |
- mk_PointerFieldAccess(qualifier, target, dominator, access) and
- new_qualifier = GVN_Deref(qualifier, dominator)
- )
-}
-
-private predicate analyzableImplicitThisFieldAccess(ImplicitThisFieldAccess access) {
- strictcount(mostRecentSideEffect(access)) = 1 and
- strictcount(access.getTarget()) = 1 and
- strictcount(access.getEnclosingFunction()) = 1 and
- not analyzableConst(access)
-}
-
-private predicate mk_ImplicitThisFieldAccess(
- Function fcn, Field target, ControlFlowNode dominator, ImplicitThisFieldAccess access
-) {
- analyzableImplicitThisFieldAccess(access) and
- dominator = mostRecentSideEffect(access) and
- target = access.getTarget() and
- fcn = access.getEnclosingFunction()
-}
-
-deprecated private predicate mk_ImplicitThisFieldAccess_with_qualifier(
- GVN qualifier, Field target, ControlFlowNode dominator, ImplicitThisFieldAccess access
-) {
- exists(Function fcn |
- mk_ImplicitThisFieldAccess(fcn, target, dominator, access) and
- qualifier = GVN_ThisExpr(fcn)
- )
-}
-
-deprecated private predicate mk_ImplicitThisFieldAccess_with_deref(
- GVN new_qualifier, Field target, ImplicitThisFieldAccess access
-) {
- exists(GVN qualifier, ControlFlowNode dominator |
- mk_ImplicitThisFieldAccess_with_qualifier(qualifier, target, dominator, access) and
- new_qualifier = GVN_Deref(qualifier, dominator)
- )
-}
-
-/**
- * Holds if `access` is an access of a variable that does
- * not have SSA information. (For example, because the variable
- * is global.)
- */
-private predicate analyzableOtherVariable(VariableAccess access) {
- not access instanceof FieldAccess and
- not exists(SsaDefinition def | access = def.getAUse(_)) and
- strictcount(access.getTarget()) = 1 and
- strictcount(mostRecentSideEffect(access)) = 1 and
- not analyzableConst(access)
-}
-
-private predicate mk_OtherVariable(Variable x, ControlFlowNode dominator, VariableAccess access) {
- analyzableOtherVariable(access) and
- x = access.getTarget() and
- dominator = mostRecentSideEffect(access)
-}
-
-private predicate analyzableConversion(Conversion conv) {
- strictcount(conv.getUnspecifiedType()) = 1 and
- strictcount(conv.getExpr()) = 1 and
- not analyzableConst(conv)
-}
-
-deprecated private predicate mk_Conversion(Type t, GVN child, Conversion conv) {
- analyzableConversion(conv) and
- t = conv.getUnspecifiedType() and
- child = globalValueNumber(conv.getExpr())
-}
-
-private predicate analyzableBinaryOp(BinaryOperation op) {
- op.isPure() and
- strictcount(op.getLeftOperand().getFullyConverted()) = 1 and
- strictcount(op.getRightOperand().getFullyConverted()) = 1 and
- strictcount(op.getOperator()) = 1 and
- not analyzableConst(op)
-}
-
-deprecated private predicate mk_BinaryOp(GVN lhs, GVN rhs, string opname, BinaryOperation op) {
- analyzableBinaryOp(op) and
- lhs = globalValueNumber(op.getLeftOperand().getFullyConverted()) and
- rhs = globalValueNumber(op.getRightOperand().getFullyConverted()) and
- opname = op.getOperator()
-}
-
-private predicate analyzableUnaryOp(UnaryOperation op) {
- not op instanceof PointerDereferenceExpr and
- op.isPure() and
- strictcount(op.getOperand().getFullyConverted()) = 1 and
- strictcount(op.getOperator()) = 1 and
- not analyzableConst(op)
-}
-
-deprecated private predicate mk_UnaryOp(GVN child, string opname, UnaryOperation op) {
- analyzableUnaryOp(op) and
- child = globalValueNumber(op.getOperand().getFullyConverted()) and
- opname = op.getOperator()
-}
-
-private predicate analyzableThisExpr(ThisExpr thisExpr) {
- strictcount(thisExpr.getEnclosingFunction()) = 1 and
- not analyzableConst(thisExpr)
-}
-
-private predicate mk_ThisExpr(Function fcn, ThisExpr thisExpr) {
- analyzableThisExpr(thisExpr) and
- fcn = thisExpr.getEnclosingFunction()
-}
-
-private predicate analyzableArrayAccess(ArrayExpr ae) {
- strictcount(ae.getArrayBase().getFullyConverted()) = 1 and
- strictcount(ae.getArrayOffset().getFullyConverted()) = 1 and
- strictcount(mostRecentSideEffect(ae)) = 1 and
- not analyzableConst(ae)
-}
-
-deprecated private predicate mk_ArrayAccess(
- GVN base, GVN offset, ControlFlowNode dominator, ArrayExpr ae
-) {
- analyzableArrayAccess(ae) and
- base = globalValueNumber(ae.getArrayBase().getFullyConverted()) and
- offset = globalValueNumber(ae.getArrayOffset().getFullyConverted()) and
- dominator = mostRecentSideEffect(ae)
-}
-
-private predicate analyzablePointerDereferenceExpr(PointerDereferenceExpr deref) {
- strictcount(deref.getOperand().getFullyConverted()) = 1 and
- strictcount(mostRecentSideEffect(deref)) = 1 and
- not analyzableConst(deref)
-}
-
-deprecated private predicate mk_Deref(GVN p, ControlFlowNode dominator, PointerDereferenceExpr deref) {
- analyzablePointerDereferenceExpr(deref) and
- p = globalValueNumber(deref.getOperand().getFullyConverted()) and
- dominator = mostRecentSideEffect(deref)
-}
-
-/** Gets the global value number of expression `e`. */
-cached
-deprecated GVN globalValueNumber(Expr e) {
- exists(int val, Type t |
- mk_IntConst(val, t, e) and
- result = GVN_IntConst(val, t)
- )
- or
- exists(float val, Type t |
- mk_FloatConst(val, t, e) and
- result = GVN_FloatConst(val, t)
- )
- or
- // Local variable with a defining value.
- exists(StackVariable x, SsaDefinition def |
- analyzableStackVariable(e) and
- e = def.getAUse(x) and
- result = globalValueNumber(def.getDefiningValue(x).getFullyConverted())
- )
- or
- // Local variable without a defining value.
- exists(StackVariable x, SsaDefinition def |
- mk_UndefinedStackVariable(x, def, e) and
- result = GVN_UndefinedStackVariable(x, def)
- )
- or
- // Variable with no SSA information.
- exists(Variable x, ControlFlowNode dominator |
- mk_OtherVariable(x, dominator, e) and
- result = GVN_OtherVariable(x, dominator)
- )
- or
- exists(GVN qualifier, Field target |
- mk_DotFieldAccess(qualifier, target, e) and
- result = GVN_FieldAccess(qualifier, target)
- )
- or
- exists(GVN qualifier, Field target |
- mk_PointerFieldAccess_with_deref(qualifier, target, e) and
- result = GVN_FieldAccess(qualifier, target)
- )
- or
- exists(GVN qualifier, Field target |
- mk_ImplicitThisFieldAccess_with_deref(qualifier, target, e) and
- result = GVN_FieldAccess(qualifier, target)
- )
- or
- exists(Function fcn |
- mk_ThisExpr(fcn, e) and
- result = GVN_ThisExpr(fcn)
- )
- or
- exists(Type t, GVN child |
- mk_Conversion(t, child, e) and
- result = GVN_Conversion(t, child)
- )
- or
- exists(GVN lhs, GVN rhs, string opname |
- mk_BinaryOp(lhs, rhs, opname, e) and
- result = GVN_BinaryOp(lhs, rhs, opname)
- )
- or
- exists(GVN child, string opname |
- mk_UnaryOp(child, opname, e) and
- result = GVN_UnaryOp(child, opname)
- )
- or
- exists(GVN x, GVN i, ControlFlowNode dominator |
- mk_ArrayAccess(x, i, dominator, e) and
- result = GVN_ArrayAccess(x, i, dominator)
- )
- or
- exists(GVN p, ControlFlowNode dominator |
- mk_Deref(p, dominator, e) and
- result = GVN_Deref(p, dominator)
- )
- or
- not analyzableExpr(e) and result = GVN_Unanalyzable(e)
-}
-
-private predicate analyzableConst(Expr e) {
- analyzableIntConst(e) or
- analyzableFloatConst(e)
-}
-
-/**
- * Holds if the expression is explicitly handled by `globalValueNumber`.
- * Unanalyzable expressions still need to be given a global value number,
- * but it will be a unique number that is not shared with any other
- * expression.
- */
-private predicate analyzableExpr(Expr e) {
- analyzableConst(e) or
- analyzableStackVariable(e) or
- analyzableDotFieldAccess(e) or
- analyzablePointerFieldAccess(e) or
- analyzableImplicitThisFieldAccess(e) or
- analyzableOtherVariable(e) or
- analyzableConversion(e) or
- analyzableBinaryOp(e) or
- analyzableUnaryOp(e) or
- analyzableThisExpr(e) or
- analyzableArrayAccess(e) or
- analyzablePointerDereferenceExpr(e)
-}
diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md
index ab33b22360c1..52ce33161a75 100644
--- a/cpp/ql/src/CHANGELOG.md
+++ b/cpp/ql/src/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 0.9.11
+
+### Minor Analysis Improvements
+
+* The "Uncontrolled data used in path expression" query (`cpp/path-injection`) query produces fewer near-duplicate results.
+* The "Global variable may be used before initialization" query (`cpp/global-use-before-init`) no longer raises an alert on global variables that are initialized when they are declared.
+* The "Inconsistent null check of pointer" query (`cpp/inconsistent-nullness-testing`) query no longer raises an alert when the guarded check is in a macro expansion.
+
## 0.9.10
No user-facing changes.
diff --git a/cpp/ql/src/Likely Bugs/Format/TooManyFormatArguments.qhelp b/cpp/ql/src/Likely Bugs/Format/TooManyFormatArguments.qhelp
index bbd64254d54c..b4df60cbac72 100644
--- a/cpp/ql/src/Likely Bugs/Format/TooManyFormatArguments.qhelp
+++ b/cpp/ql/src/Likely Bugs/Format/TooManyFormatArguments.qhelp
@@ -22,10 +22,8 @@ function.
-cplusplus.com: C++ Functions.
+CERT C Coding Standard: FIO47-C. Use valid format strings.
Microsoft C Runtime Library Reference: printf, wprintf.
-
-
diff --git a/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.qhelp b/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.qhelp
index 66344e93f22d..bb4687b2d9a7 100644
--- a/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.qhelp
+++ b/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.qhelp
@@ -19,8 +19,8 @@ contents.
-Review the format and arguments expected by the highlighted function calls. Update either
-the format or the arguments so that the expected number of arguments are passed to the
+
Review the format and arguments expected by the highlighted function calls. Update either
+the format or the arguments so that the expected number of arguments are passed to the
function.
@@ -30,11 +30,8 @@ function.
-CERT C Coding
-Standard: FIO30-C. Exclude user input from format strings.
-cplusplus.com: C++ Functions.
+CERT C Coding Standard: FIO47-C. Use valid format strings.
Microsoft C Runtime Library Reference: printf, wprintf.
-
diff --git a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.cpp b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.cpp
deleted file mode 100644
index c3dd09c30719..000000000000
--- a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-int main() {
- printf("%s\n", 42); //printf will treat 42 as a char*, will most likely segfault
- return 0;
-}
diff --git a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.qhelp b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.qhelp
index 02bfd391a330..055adeb741f3 100644
--- a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.qhelp
+++ b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.qhelp
@@ -4,29 +4,33 @@
Each call to the printf
function or a related function should include
-the type and sequence of arguments defined by the format. If the function is passed arguments
+the type and sequence of arguments defined by the format. If the function is passed arguments
of a different type or in a different sequence then the arguments are reinterpreted to fit the type and sequence expected, resulting in unpredictable behavior.
-Review the format and arguments expected by the highlighted function calls. Update either
-the format or the arguments so that the expected type and sequence of arguments are passed to
+
Review the format and arguments expected by the highlighted function calls. Update either
+the format or the arguments so that the expected type and sequence of arguments are passed to
the function.
-
+
-
-
+In the following example, the wrong format specifier is given for an integer format argument:
+
+
-CERT C Coding
-Standard: FIO30-C. Exclude user input from format strings.
-cplusplus.com: C++ Functions.
-CRT Alphabetical Function Reference: printf, _printf_l, wprintf, _wprintf_l.
+The corrected version uses %i
as the format specifier for the integer format argument:
+
+
+
+Microsoft Learn: Format specification syntax: printf and wprintf functions.
+cplusplus.com:printf
+CERT C Coding Standard: FIO47-C. Use valid format strings.
diff --git a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArgumentsBad.cpp b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArgumentsBad.cpp
new file mode 100644
index 000000000000..046233af1b00
--- /dev/null
+++ b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArgumentsBad.cpp
@@ -0,0 +1,4 @@
+int main() {
+ printf("%s\n", 42); // BAD: printf will treat 42 as a char*, will most likely segfault
+ return 0;
+}
diff --git a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArgumentsGood.cpp b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArgumentsGood.cpp
new file mode 100644
index 000000000000..0bd3fb5c4391
--- /dev/null
+++ b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArgumentsGood.cpp
@@ -0,0 +1,4 @@
+int main() {
+ printf("%i\n", 42); // GOOD: printf will treat 42 as an int
+ return 0;
+}
diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.cpp b/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.cpp
index c3640a66ab6f..29eef7c2b1f5 100644
--- a/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.cpp
+++ b/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.cpp
@@ -2,19 +2,18 @@
void f_warning(int i)
{
- // The usage of the logical not operator in this case is unlikely to be correct
+ // BAD: the usage of the logical not operator in this case is unlikely to be correct
// as the output is being used as an operator for a bit-wise and operation
- if (i & !FLAGS)
+ if (i & !FLAGS)
{
// code
}
}
-
void f_fixed(int i)
{
- if (i & ~FLAGS) // Changing the logical not operator for the bit-wise not operator would fix this logic
+ if (i & ~FLAGS) // GOOD: Changing the logical not operator for the bit-wise not operator would fix this logic
{
// code
}
-}
\ No newline at end of file
+}
diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.qhelp b/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.qhelp
index bac09fe9cf17..3b5824c314a3 100644
--- a/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.qhelp
+++ b/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.qhelp
@@ -16,7 +16,13 @@
Carefully inspect the flagged expressions. Consider the intent in the code logic, and decide whether it is necessary to change the not operator.
-
+
+Here is an example of this issue and how it can be fixed:
+
+
+
+In other cases, particularly when the expressions have bool
type, the fix may instead be of the form a && !b
.
+
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.cpp b/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.cpp
deleted file mode 100644
index 07acc91cd5ac..000000000000
--- a/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-strncpy(dest, src, sizeof(src)); //wrong: size of dest should be used
-strncpy(dest, src, strlen(src)); //wrong: size of dest should be used
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.qhelp b/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.qhelp
index 2e297116710f..201b9057499a 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.qhelp
+++ b/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.qhelp
@@ -3,7 +3,7 @@
"qhelp.dtd">
-The standard library function strncpy
copies a source string to a destination buffer. The third argument defines the maximum number of characters to copy and should be less than
+
The standard library function strncpy
copies a source string to a destination buffer. The third argument defines the maximum number of characters to copy and should be less than
or equal to the size of the destination buffer. Calls of the form strncpy(dest, src, strlen(src))
or strncpy(dest, src, sizeof(src))
incorrectly set the third argument to the size of the source buffer. Executing a call of this type may cause a buffer overflow. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability.
@@ -12,14 +12,20 @@ or equal to the size of the destination buffer. Calls of the form strncpy(
not the source buffer.
-
+
+In the following examples, the size of the source buffer is incorrectly used as a parameter to strncpy
:
+
+The corrected version uses the size of the destination buffer, or a variable containing the size of the destination buffer as the size parameter to strncpy
:
+
+
+
-cplusplus.com: strncpy.
+cplusplus.com: strncpy.
I. Gerg. An Overview and Example of the Buffer-Overflow Exploit. IANewsletter vol 7 no 4. 2005.
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgsBad.cpp b/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgsBad.cpp
new file mode 100644
index 000000000000..952550b26382
--- /dev/null
+++ b/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgsBad.cpp
@@ -0,0 +1,9 @@
+char src[256];
+char dest1[128];
+
+...
+
+strncpy(dest1, src, sizeof(src)); // wrong: size of dest should be used
+
+char *dest2 = (char *)malloc(sz1 + sz2 + sz3);
+strncpy(dest2, src, strlen(src)); // wrong: size of dest should be used
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgsGood.cpp b/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgsGood.cpp
new file mode 100644
index 000000000000..22fc4ebd2220
--- /dev/null
+++ b/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgsGood.cpp
@@ -0,0 +1,10 @@
+char src[256];
+char dest1[128];
+
+...
+
+strncpy(dest1, src, sizeof(dest1)); // correct
+
+size_t destSize = sz1 + sz2 + sz3;
+char *dest2 = (char *)malloc(destSize);
+strncpy(dest2, src, destSize); // correct
diff --git a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql
index 4e626d0bc773..94a9cacf9f49 100644
--- a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql
+++ b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql
@@ -88,6 +88,11 @@ module TaintedPathConfig implements DataFlow::ConfigSig {
hasUpperBoundsCheck(checkedVar)
)
}
+
+ predicate isBarrierOut(DataFlow::Node node) {
+ // make sinks barriers so that we only report the closest instance
+ isSink(node)
+ }
}
module TaintedPath = TaintTracking::Global;
diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.qhelp b/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.qhelp
similarity index 84%
rename from cpp/ql/src/experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.qhelp
rename to cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.qhelp
index 19975b174932..87cc75c5f019 100644
--- a/cpp/ql/src/experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.qhelp
+++ b/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.qhelp
@@ -30,6 +30,12 @@ This is because the temporary container is not bound to a rvalue reference.
+
+To fix lifetime_of_temp_not_extended
, consider rewriting the code so that the lifetime of the temporary object is extended.
+In fixed_lifetime_of_temp_not_extended
, the lifetime of the temporary object has been extended by storing it in an rvalue reference.
+
+
+
diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.ql b/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
similarity index 72%
rename from cpp/ql/src/experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
rename to cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
index a36e54070bbe..139555cfa1d6 100644
--- a/cpp/ql/src/experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
+++ b/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
@@ -2,9 +2,10 @@
* @name Iterator to expired container
* @description Using an iterator owned by a container whose lifetime has expired may lead to unexpected behavior.
* @kind problem
- * @precision high
+ * @precision medium
* @id cpp/iterator-to-expired-container
* @problem.severity warning
+ * @security-severity 8.8
* @tags reliability
* security
* external/cwe/cwe-416
@@ -61,14 +62,38 @@ DataFlow::Node getADestroyedNode(DataFlow::Node n) {
)
}
-predicate destroyedToBeginSink(DataFlow::Node sink, FunctionCall fc) {
+predicate destroyedToBeginSink(DataFlow::Node sink) {
exists(CallInstruction call |
call = sink.asOperand().(ThisArgumentOperand).getCall() and
- fc = call.getUnconvertedResultExpression() and
call.getStaticCallTarget() instanceof BeginOrEndFunction
)
}
+/**
+ * Holds if `node1` is the node corresponding to a qualifier of a destructor
+ * call and `node2` is a node that is destroyed as a result of `node1` being
+ * destroyed.
+ */
+private predicate qualifierToDestroyed(DataFlow::Node node1, DataFlow::Node node2) {
+ tempToDestructorSink(node1, _) and
+ node2 = getADestroyedNode(node1)
+}
+
+/**
+ * A configuration to track flow from a destroyed node to a qualifier of
+ * a `begin` or `end` function call.
+ *
+ * This configuration exists to prevent a cartesian product between all sinks and
+ * all states in `Config::isSink`.
+ */
+module Config0 implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) { qualifierToDestroyed(_, source) }
+
+ predicate isSink(DataFlow::Node sink) { destroyedToBeginSink(sink) }
+}
+
+module Flow0 = DataFlow::Global;
+
/**
* A configuration to track flow from a temporary variable to the qualifier of
* a destructor call, and subsequently to a qualifier of a call to `begin` or
@@ -78,12 +103,15 @@ module Config implements DataFlow::StateConfigSig {
newtype FlowState =
additional TempToDestructor() or
additional DestroyedToBegin(DataFlow::Node n) {
- exists(DataFlow::Node thisOperand |
- tempToDestructorSink(thisOperand, _) and
- n = getADestroyedNode(thisOperand)
- )
+ any(Flow0::PathNode pn | pn.isSource()).getNode() = n
}
+ /**
+ * Holds if `sink` is a qualifier to a call to `begin`, and `mid` is an
+ * object that is destroyed.
+ */
+ private predicate relevant(DataFlow::Node mid, DataFlow::Node sink) { Flow0::flow(mid, sink) }
+
predicate isSource(DataFlow::Node source, FlowState state) {
source.asInstruction().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable and
state = TempToDestructor()
@@ -92,16 +120,16 @@ module Config implements DataFlow::StateConfigSig {
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
- tempToDestructorSink(node1, _) and
state1 = TempToDestructor() and
state2 = DestroyedToBegin(node2) and
- node2 = getADestroyedNode(node1)
+ qualifierToDestroyed(node1, node2)
}
predicate isSink(DataFlow::Node sink, FlowState state) {
- // Note: This is a non-trivial cartesian product!
- // Hopefully, both of these sets are quite small in practice
- destroyedToBeginSink(sink, _) and state instanceof DestroyedToBegin
+ exists(DataFlow::Node mid |
+ relevant(mid, sink) and
+ state = DestroyedToBegin(mid)
+ )
}
DataFlow::FlowFeature getAFeature() {
@@ -121,9 +149,9 @@ module Config implements DataFlow::StateConfigSig {
module Flow = DataFlow::GlobalWithState;
-from Flow::PathNode source, Flow::PathNode sink, FunctionCall beginOrEnd, DataFlow::Node mid
+from Flow::PathNode source, Flow::PathNode sink, DataFlow::Node mid
where
Flow::flowPath(source, sink) and
- destroyedToBeginSink(sink.getNode(), beginOrEnd) and
+ destroyedToBeginSink(sink.getNode()) and
sink.getState() = Config::DestroyedToBegin(mid)
-select mid, "This object is destroyed before $@ is called.", beginOrEnd, beginOrEnd.toString()
+select mid, "This object is destroyed at the end of the full-expression."
diff --git a/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainerExtendedLifetime-fixed.cpp b/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainerExtendedLifetime-fixed.cpp
new file mode 100644
index 000000000000..d113b4165ff7
--- /dev/null
+++ b/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainerExtendedLifetime-fixed.cpp
@@ -0,0 +1,6 @@
+void fixed_lifetime_of_temp_not_extended() {
+ auto&& v = get_vector();
+ for(auto x : log_and_return_argument(v)) {
+ use(x); // GOOD: The lifetime of the container returned by `get_vector()` has been extended to the lifetime of `v`.
+ }
+}
diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-416/IteratorToExpiredContainerExtendedLifetime.cpp b/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainerExtendedLifetime.cpp
similarity index 100%
rename from cpp/ql/src/experimental/Security/CWE/CWE-416/IteratorToExpiredContainerExtendedLifetime.cpp
rename to cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainerExtendedLifetime.cpp
diff --git a/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.qhelp b/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.qhelp
index e0678c0beff2..3a449b4c38c3 100644
--- a/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.qhelp
+++ b/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.qhelp
@@ -8,6 +8,12 @@
When the std::string
object is destroyed, the pointer returned by c_str
is no
longer valid. If the pointer is used after the std::string
object is destroyed, then the behavior is undefined.
+
+Typically, this problem occurs when a std::string
is returned by a function call (or overloaded operator)
+by value, and the result is not immediately stored in a variable by value or reference in a way that extends the lifetime of
+the temporary object. The resulting temporary std::string
object is destroyed at the end of the containing expression
+statement, along with any memory returned by a call to c_str
.
+
@@ -39,6 +45,8 @@ points to valid memory.
MEM50-CPP. Do not access freed memory.
+Microsoft Learn: Temporary objects.
+cppreference.com: Lifetime of a temporary.
diff --git a/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.ql b/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.ql
index 7d776280f917..982486759082 100644
--- a/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.ql
+++ b/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.ql
@@ -23,4 +23,5 @@ where
(c.getTarget() instanceof StdStringCStr or c.getTarget() instanceof StdStringData) and
isTemporary(c.getQualifier().getFullyConverted())
select c,
- "The underlying string object is destroyed after the call to '" + c.getTarget() + "' returns."
+ "The underlying temporary string object is destroyed after the call to '" + c.getTarget() +
+ "' returns."
diff --git a/cpp/ql/src/change-notes/2024-04-29-iterator-to-expired-container.md b/cpp/ql/src/change-notes/2024-04-29-iterator-to-expired-container.md
new file mode 100644
index 000000000000..ce06805a8f37
--- /dev/null
+++ b/cpp/ql/src/change-notes/2024-04-29-iterator-to-expired-container.md
@@ -0,0 +1,4 @@
+---
+category: newQuery
+---
+* Added a new query, `cpp/iterator-to-expired-container`, to detect the creation of iterators owned by a temporary objects that are about to be destroyed.
diff --git a/cpp/ql/src/change-notes/2024-04-09-reduce-FP.md b/cpp/ql/src/change-notes/released/0.9.11.md
similarity index 60%
rename from cpp/ql/src/change-notes/2024-04-09-reduce-FP.md
rename to cpp/ql/src/change-notes/released/0.9.11.md
index d2d104d59cd8..41ffd2f0d06b 100644
--- a/cpp/ql/src/change-notes/2024-04-09-reduce-FP.md
+++ b/cpp/ql/src/change-notes/released/0.9.11.md
@@ -1,5 +1,7 @@
----
-category: minorAnalysis
----
+## 0.9.11
+
+### Minor Analysis Improvements
+
+* The "Uncontrolled data used in path expression" query (`cpp/path-injection`) query produces fewer near-duplicate results.
* The "Global variable may be used before initialization" query (`cpp/global-use-before-init`) no longer raises an alert on global variables that are initialized when they are declared.
-* The "Inconsistent null check of pointer" query (`cpp/inconsistent-nullness-testing`) query no longer raises an alert when the guarded check is in a macro expansion.
\ No newline at end of file
+* The "Inconsistent null check of pointer" query (`cpp/inconsistent-nullness-testing`) query no longer raises an alert when the guarded check is in a macro expansion.
diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml
index d086ed69541d..47eb8b55bab8 100644
--- a/cpp/ql/src/codeql-pack.release.yml
+++ b/cpp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.9.10
+lastReleaseVersion: 0.9.11
diff --git a/cpp/ql/src/experimental/Best Practices/GuardedFree.cpp b/cpp/ql/src/experimental/Best Practices/GuardedFree.cpp
new file mode 100644
index 000000000000..5242e3da8f5e
--- /dev/null
+++ b/cpp/ql/src/experimental/Best Practices/GuardedFree.cpp
@@ -0,0 +1,11 @@
+void test()
+{
+ char *foo = malloc(100);
+
+ // BAD
+ if (foo)
+ free(foo);
+
+ // GOOD
+ free(foo);
+}
\ No newline at end of file
diff --git a/cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp b/cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp
new file mode 100644
index 000000000000..77fdd4670008
--- /dev/null
+++ b/cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp
@@ -0,0 +1,18 @@
+
+
+
+The free
function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check its argument for the value of NULL before a function call to free
. As such, these guards may hinder performance and readability.
+
+
+A function call to free
should not depend upon the value of its argument. Delete the if
condition preceeding a function call to free
when its only purpose is to check the value of the pointer to be freed.
+
+
+
+
+
+
+ The Open Group Base Specifications Issue 7, 2018 Edition:
+ free - free allocated memory
+
+
+
\ No newline at end of file
diff --git a/cpp/ql/src/experimental/Best Practices/GuardedFree.ql b/cpp/ql/src/experimental/Best Practices/GuardedFree.ql
new file mode 100644
index 000000000000..2d504d9bc057
--- /dev/null
+++ b/cpp/ql/src/experimental/Best Practices/GuardedFree.ql
@@ -0,0 +1,26 @@
+/**
+ * @name Guarded Free
+ * @description NULL-condition guards before function calls to the memory-deallocation
+ * function free(3) are unnecessary, because passing NULL to free(3) is a no-op.
+ * @kind problem
+ * @problem.severity recommendation
+ * @precision very-high
+ * @id cpp/guarded-free
+ * @tags maintainability
+ * readability
+ * experimental
+ */
+
+import cpp
+import semmle.code.cpp.controlflow.Guards
+
+class FreeCall extends FunctionCall {
+ FreeCall() { this.getTarget().hasGlobalName("free") }
+}
+
+from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb
+where
+ gc.ensuresEq(v.getAnAccess(), 0, bb, false) and
+ fc.getArgument(0) = v.getAnAccess() and
+ bb = fc.getEnclosingStmt()
+select gc, "unnecessary NULL check before call to $@", fc, "free"
diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-125/DangerousWorksWithMultibyteOrWideCharacters.ql b/cpp/ql/src/experimental/Security/CWE/CWE-125/DangerousWorksWithMultibyteOrWideCharacters.ql
index 12a44be0d1fc..6529bf6cdf89 100644
--- a/cpp/ql/src/experimental/Security/CWE/CWE-125/DangerousWorksWithMultibyteOrWideCharacters.ql
+++ b/cpp/ql/src/experimental/Security/CWE/CWE-125/DangerousWorksWithMultibyteOrWideCharacters.ql
@@ -24,7 +24,7 @@ predicate exprMayBeString(Expr exp) {
fctmp.getAnArgument().(VariableAccess).getTarget() = exp.(VariableAccess).getTarget() or
globalValueNumber(fctmp.getAnArgument()) = globalValueNumber(exp)
) and
- fctmp.getTarget().hasName(["strlen", "strcat", "strncat", "strcpy", "sptintf", "printf"])
+ fctmp.getTarget().hasName(["strlen", "strcat", "strncat", "strcpy", "sprintf", "printf"])
)
or
exists(AssignExpr astmp |
diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml
index 3fe23a7cbbad..e3f87e5a6356 100644
--- a/cpp/ql/src/qlpack.yml
+++ b/cpp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-queries
-version: 0.9.11-dev
+version: 0.9.12-dev
groups:
- cpp
- queries
diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-416/IteratorToExpiredContainer.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-416/IteratorToExpiredContainer.expected
deleted file mode 100644
index c29e7953ea64..000000000000
--- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-416/IteratorToExpiredContainer.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to begin | call to begin |
-| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to end | call to end |
-| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to begin | call to begin |
-| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to end | call to end |
-| test.cpp:689:46:689:58 | pointer to ~vector output argument | This object is destroyed before $@ is called. | test.cpp:689:60:689:62 | call to end | call to end |
-| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:19:703:23 | call to begin | call to begin |
-| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:36:703:38 | call to end | call to end |
-| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to begin | call to begin |
-| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to end | call to end |
-| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to begin | call to begin |
-| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to end | call to end |
diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-416/IteratorToExpiredContainer.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-416/IteratorToExpiredContainer.qlref
deleted file mode 100644
index 5f86bb26ff09..000000000000
--- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-416/IteratorToExpiredContainer.qlref
+++ /dev/null
@@ -1 +0,0 @@
-experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
diff --git a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected
index cc29559d5d31..d50ca1609163 100644
--- a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected
+++ b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected
@@ -56,6 +56,8 @@ astGuardsCompare
| 17 | y < 1+1 when ... > ... is false |
| 17 | y >= 1+1 when ... && ... is true |
| 17 | y >= 1+1 when ... > ... is true |
+| 18 | call to get != 0 when call to get is true |
+| 18 | call to get == 0 when call to get is false |
| 26 | 0 < x+0 when ... > ... is true |
| 26 | 0 >= x+0 when ... > ... is false |
| 26 | x < 0+1 when ... > ... is false |
@@ -146,6 +148,24 @@ astGuardsCompare
| 109 | y < 0+0 when ... < ... is true |
| 109 | y >= 0+0 when ... < ... is false |
| 109 | y >= 0+0 when ... \|\| ... is false |
+| 126 | 1 != 0 when 1 is true |
+| 126 | 1 != 0 when ... && ... is true |
+| 126 | 1 == 0 when 1 is false |
+| 126 | call to test3_condition != 0 when ... && ... is true |
+| 126 | call to test3_condition != 0 when call to test3_condition is true |
+| 126 | call to test3_condition == 0 when call to test3_condition is false |
+| 131 | b != 0 when b is true |
+| 131 | b == 0 when b is false |
+| 137 | 0 != 0 when 0 is true |
+| 137 | 0 == 0 when 0 is false |
+| 146 | ! ... != 0 when ! ... is true |
+| 146 | ! ... == 0 when ! ... is false |
+| 152 | x != 0 when ... && ... is true |
+| 152 | x != 0 when x is true |
+| 152 | x == 0 when x is false |
+| 152 | y != 0 when ... && ... is true |
+| 152 | y != 0 when y is true |
+| 152 | y == 0 when y is false |
| 156 | ... + ... != x+0 when ... == ... is false |
| 156 | ... + ... == x+0 when ... == ... is true |
| 156 | x != ... + ...+0 when ... == ... is false |
@@ -184,6 +204,8 @@ astGuardsCompare
| 175 | call to foo != 0+0 when ... == ... is false |
| 175 | call to foo == 0 when ... == ... is true |
| 175 | call to foo == 0+0 when ... == ... is true |
+| 181 | x != 0 when x is true |
+| 181 | x == 0 when x is false |
astGuardsControl
| test.c:7:9:7:13 | ... > ... | false | 10 | 11 |
| test.c:7:9:7:13 | ... > ... | true | 7 | 9 |
@@ -485,8 +507,28 @@ astGuardsEnsure_const
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 109 | 109 |
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
+| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 |
+| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
+| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 |
+| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 |
+| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 |
+| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
+| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
+| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
+| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
+| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
+| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 |
+| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 151 | 152 |
+| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 152 | 152 |
+| test.c:152:10:152:15 | ... && ... | test.c:152:10:152:10 | x | != | 0 | 151 | 152 |
+| test.c:152:10:152:15 | ... && ... | test.c:152:15:152:15 | y | != | 0 | 151 | 152 |
+| test.c:152:15:152:15 | y | test.c:152:15:152:15 | y | != | 0 | 151 | 152 |
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | != | 0 | 175 | 175 |
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | == | 0 | 175 | 175 |
+| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 181 | 182 |
+| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 186 | 180 |
+| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | == | 0 | 183 | 184 |
+| test.cpp:18:8:18:10 | call to get | test.cpp:18:8:18:10 | call to get | != | 0 | 19 | 19 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 30 | 30 |
@@ -545,6 +587,8 @@ irGuardsCompare
| 17 | y < 2 when CompareGT: ... > ... is false |
| 17 | y >= 1+1 when CompareGT: ... > ... is true |
| 17 | y >= 2 when CompareGT: ... > ... is true |
+| 18 | call to get != 0 when CompareNE: (bool)... is true |
+| 18 | call to get == 0 when CompareNE: (bool)... is false |
| 26 | 0 < x+0 when CompareGT: ... > ... is true |
| 26 | 0 >= x+0 when CompareGT: ... > ... is false |
| 26 | x < 0+1 when CompareGT: ... > ... is false |
@@ -635,6 +679,20 @@ irGuardsCompare
| 109 | y < 0+0 when CompareLT: ... < ... is true |
| 109 | y >= 0 when CompareLT: ... < ... is false |
| 109 | y >= 0+0 when CompareLT: ... < ... is false |
+| 126 | 1 != 0 when Constant: 1 is true |
+| 126 | 1 == 0 when Constant: 1 is false |
+| 126 | call to test3_condition != 0 when Call: call to test3_condition is true |
+| 126 | call to test3_condition == 0 when Call: call to test3_condition is false |
+| 131 | b != 0 when Load: b is true |
+| 131 | b == 0 when Load: b is false |
+| 137 | 0 != 0 when Constant: 0 is true |
+| 137 | 0 == 0 when Constant: 0 is false |
+| 146 | ! ... != 0 when LogicalNot: ! ... is true |
+| 146 | ! ... == 0 when LogicalNot: ! ... is false |
+| 152 | x != 0 when Load: x is true |
+| 152 | x == 0 when Load: x is false |
+| 152 | y != 0 when Load: y is true |
+| 152 | y == 0 when Load: y is false |
| 156 | ... + ... != x+0 when CompareEQ: ... == ... is false |
| 156 | ... + ... == x+0 when CompareEQ: ... == ... is true |
| 156 | x != ... + ...+0 when CompareEQ: ... == ... is false |
@@ -673,6 +731,8 @@ irGuardsCompare
| 175 | call to foo != 0+0 when CompareEQ: ... == ... is false |
| 175 | call to foo == 0 when CompareEQ: ... == ... is true |
| 175 | call to foo == 0+0 when CompareEQ: ... == ... is true |
+| 181 | x != 0 when Load: x is true |
+| 181 | x == 0 when Load: x is false |
irGuardsControl
| test.c:7:9:7:13 | CompareGT: ... > ... | false | 11 | 11 |
| test.c:7:9:7:13 | CompareGT: ... > ... | true | 8 | 8 |
@@ -994,8 +1054,22 @@ irGuardsEnsure_const
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 109 | 109 |
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 113 | 113 |
| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:19 | Load: y | >= | 0 | 113 | 113 |
+| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 126 | 126 |
+| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 127 | 127 |
+| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 131 | 131 |
+| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 132 | 132 |
+| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 134 | 134 |
+| test.c:126:12:126:26 | Call: call to test3_condition | test.c:126:12:126:26 | Call: call to test3_condition | != | 0 | 127 | 127 |
+| test.c:131:7:131:7 | Load: b | test.c:131:7:131:7 | Load: b | != | 0 | 132 | 132 |
+| test.c:137:7:137:7 | Constant: 0 | test.c:137:7:137:7 | Constant: 0 | == | 0 | 142 | 142 |
+| test.c:146:7:146:8 | LogicalNot: ! ... | test.c:146:7:146:8 | LogicalNot: ! ... | != | 0 | 147 | 147 |
+| test.c:152:10:152:10 | Load: x | test.c:152:10:152:10 | Load: x | != | 0 | 152 | 152 |
+| test.c:152:15:152:15 | Load: y | test.c:152:15:152:15 | Load: y | != | 0 | 152 | 152 |
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | != | 0 | 175 | 175 |
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | == | 0 | 175 | 175 |
+| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | != | 0 | 182 | 182 |
+| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | == | 0 | 184 | 184 |
+| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | 0 | 19 | 19 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | -1 | 34 | 34 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 30 | 30 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 32 | 32 |
diff --git a/cpp/ql/test/library-tests/controlflow/guards/Guards.expected b/cpp/ql/test/library-tests/controlflow/guards/Guards.expected
index 6eebc960ce3c..13d6c2b654ff 100644
--- a/cpp/ql/test/library-tests/controlflow/guards/Guards.expected
+++ b/cpp/ql/test/library-tests/controlflow/guards/Guards.expected
@@ -26,9 +26,19 @@
| test.c:137:7:137:7 | 0 |
| test.c:146:7:146:8 | ! ... |
| test.c:146:8:146:8 | x |
+| test.c:152:8:152:8 | p |
+| test.c:158:8:158:9 | ! ... |
+| test.c:158:9:158:9 | p |
+| test.c:164:8:164:8 | s |
+| test.c:170:8:170:9 | ! ... |
+| test.c:170:9:170:9 | s |
| test.cpp:18:8:18:10 | call to get |
| test.cpp:31:7:31:13 | ... == ... |
| test.cpp:42:13:42:20 | call to getABool |
| test.cpp:61:10:61:10 | i |
| test.cpp:74:10:74:10 | i |
| test.cpp:84:10:84:10 | i |
+| test.cpp:93:6:93:6 | c |
+| test.cpp:99:6:99:6 | f |
+| test.cpp:105:6:105:14 | ... != ... |
+| test.cpp:111:6:111:14 | ... != ... |
diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected
index b88856d90cf0..a2f418b3d7bb 100644
--- a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected
+++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected
@@ -22,6 +22,8 @@
| 17 | y >= 1+1 when ... > ... is true |
| 17 | y >= 2 when ... && ... is true |
| 17 | y >= 2 when ... > ... is true |
+| 18 | call to get != 0 when call to get is true |
+| 18 | call to get == 0 when call to get is false |
| 26 | 0 < x+0 when ... > ... is true |
| 26 | 0 >= x+0 when ... > ... is false |
| 26 | x < 0+1 when ... > ... is false |
@@ -107,6 +109,8 @@
| 85 | y != 0+0 when ... && ... is true |
| 85 | y == 0 when ... != ... is false |
| 85 | y == 0+0 when ... != ... is false |
+| 93 | c != 0 when c is true |
+| 93 | c == 0 when c is false |
| 94 | 0 != x+0 when ... != ... is true |
| 94 | 0 == x+0 when ... != ... is false |
| 94 | x != 0 when ... != ... is true |
@@ -119,6 +123,10 @@
| 102 | j < 10+0 when ... < ... is true |
| 102 | j >= 10 when ... < ... is false |
| 102 | j >= 10+0 when ... < ... is false |
+| 105 | 0.0 != f+0 when ... != ... is true |
+| 105 | 0.0 == f+0 when ... != ... is false |
+| 105 | f != 0.0+0 when ... != ... is true |
+| 105 | f == 0.0+0 when ... != ... is false |
| 109 | 0 != x+0 when ... == ... is false |
| 109 | 0 != x+0 when ... \|\| ... is false |
| 109 | 0 < y+1 when ... < ... is false |
@@ -137,3 +145,27 @@
| 109 | y >= 0 when ... \|\| ... is false |
| 109 | y >= 0+0 when ... < ... is false |
| 109 | y >= 0+0 when ... \|\| ... is false |
+| 111 | 0.0 != i+0 when ... != ... is true |
+| 111 | 0.0 == i+0 when ... != ... is false |
+| 111 | i != 0.0+0 when ... != ... is true |
+| 111 | i == 0.0+0 when ... != ... is false |
+| 126 | 1 != 0 when 1 is true |
+| 126 | 1 != 0 when ... && ... is true |
+| 126 | 1 == 0 when 1 is false |
+| 126 | call to test3_condition != 0 when ... && ... is true |
+| 126 | call to test3_condition != 0 when call to test3_condition is true |
+| 126 | call to test3_condition == 0 when call to test3_condition is false |
+| 131 | b != 0 when b is true |
+| 131 | b == 0 when b is false |
+| 137 | 0 != 0 when 0 is true |
+| 137 | 0 == 0 when 0 is false |
+| 146 | ! ... != 0 when ! ... is true |
+| 146 | ! ... == 0 when ! ... is false |
+| 152 | p != 0 when p is true |
+| 152 | p == 0 when p is false |
+| 158 | ! ... != 0 when ! ... is true |
+| 158 | ! ... == 0 when ! ... is false |
+| 164 | s != 0 when s is true |
+| 164 | s == 0 when s is false |
+| 170 | ! ... != 0 when ! ... is true |
+| 170 | ! ... == 0 when ! ... is false |
diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected
index fbfaff9acf6b..cf36a58a515b 100644
--- a/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected
+++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected
@@ -79,6 +79,12 @@
| test.c:137:7:137:7 | 0 | false | 142 | 136 |
| test.c:146:7:146:8 | ! ... | true | 146 | 147 |
| test.c:146:8:146:8 | x | false | 146 | 147 |
+| test.c:152:8:152:8 | p | true | 152 | 154 |
+| test.c:158:8:158:9 | ! ... | true | 158 | 160 |
+| test.c:158:9:158:9 | p | false | 158 | 160 |
+| test.c:164:8:164:8 | s | true | 164 | 166 |
+| test.c:170:8:170:9 | ! ... | true | 170 | 172 |
+| test.c:170:9:170:9 | s | false | 170 | 172 |
| test.cpp:18:8:18:10 | call to get | true | 19 | 19 |
| test.cpp:31:7:31:13 | ... == ... | false | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | false | 34 | 34 |
@@ -90,3 +96,7 @@
| test.cpp:61:10:61:10 | i | Case[1] | 65 | 66 |
| test.cpp:74:10:74:10 | i | Case[0..10] | 75 | 77 |
| test.cpp:74:10:74:10 | i | Case[11..20] | 78 | 79 |
+| test.cpp:93:6:93:6 | c | true | 93 | 94 |
+| test.cpp:99:6:99:6 | f | true | 99 | 100 |
+| test.cpp:105:6:105:14 | ... != ... | true | 105 | 106 |
+| test.cpp:111:6:111:14 | ... != ... | true | 111 | 112 |
diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected
index e5328aefa629..45d63f6dd536 100644
--- a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected
+++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected
@@ -1,3 +1,4 @@
+binary
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | < | test.c:7:13:7:13 | 0 | 1 | 10 | 11 |
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | >= | test.c:7:13:7:13 | 0 | 1 | 7 | 9 |
| test.c:7:9:7:13 | ... > ... | test.c:7:13:7:13 | 0 | < | test.c:7:9:7:9 | x | 0 | 7 | 9 |
@@ -154,3 +155,109 @@
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | != | test.cpp:31:7:31:7 | x | 0 | 34 | 34 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | == | test.cpp:31:7:31:7 | x | 0 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | == | test.cpp:31:7:31:7 | x | 0 | 31 | 32 |
+| test.cpp:105:6:105:14 | ... != ... | test.cpp:105:6:105:6 | f | != | test.cpp:105:11:105:14 | 0.0 | 0 | 105 | 106 |
+| test.cpp:105:6:105:14 | ... != ... | test.cpp:105:11:105:14 | 0.0 | != | test.cpp:105:6:105:6 | f | 0 | 105 | 106 |
+| test.cpp:111:6:111:14 | ... != ... | test.cpp:111:6:111:6 | i | != | test.cpp:111:11:111:14 | 0.0 | 0 | 111 | 112 |
+| test.cpp:111:6:111:14 | ... != ... | test.cpp:111:11:111:14 | 0.0 | != | test.cpp:111:6:111:6 | i | 0 | 111 | 112 |
+unary
+| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | < | 1 | 10 | 11 |
+| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | >= | 1 | 7 | 9 |
+| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:8 | x | < | 0 | 17 | 17 |
+| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:8 | x | < | 0 | 18 | 18 |
+| test.c:17:8:17:21 | ... && ... | test.c:17:8:17:8 | x | < | 0 | 18 | 18 |
+| test.c:17:8:17:21 | ... && ... | test.c:17:17:17:17 | y | >= | 2 | 18 | 18 |
+| test.c:17:17:17:21 | ... > ... | test.c:17:17:17:17 | y | >= | 2 | 18 | 18 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 2 | 2 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 31 | 34 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 34 | 34 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 39 | 42 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 42 | 42 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 42 | 44 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 45 | 45 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 45 | 47 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 51 | 53 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 56 | 58 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 58 | 58 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 58 | 66 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 62 | 62 |
+| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | >= | 1 | 26 | 28 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | < | 10 | 34 | 34 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 2 | 2 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 39 | 42 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 42 | 42 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 42 | 44 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 45 | 45 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 45 | 47 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 51 | 53 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 56 | 58 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 58 | 58 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 58 | 66 |
+| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 62 | 62 |
+| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 42 | 42 |
+| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 42 | 44 |
+| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 45 | 45 |
+| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 45 | 47 |
+| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 51 | 53 |
+| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | 1 | 42 | 42 |
+| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | 1 | 51 | 53 |
+| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | 1 | 45 | 45 |
+| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | 1 | 45 | 47 |
+| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:16 | y | >= | 1 | 45 | 47 |
+| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | 0 | 58 | 58 |
+| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | 0 | 62 | 62 |
+| test.c:58:9:58:23 | ... \|\| ... | test.c:58:9:58:9 | x | != | 0 | 62 | 62 |
+| test.c:58:9:58:23 | ... \|\| ... | test.c:58:19:58:19 | y | >= | 0 | 62 | 62 |
+| test.c:58:19:58:23 | ... < ... | test.c:58:19:58:19 | y | >= | 0 | 62 | 62 |
+| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | != | 0 | 78 | 79 |
+| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | == | 0 | 75 | 77 |
+| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | 0 | 85 | 85 |
+| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | 0 | 86 | 86 |
+| test.c:85:8:85:23 | ... && ... | test.c:85:8:85:8 | x | == | 0 | 86 | 86 |
+| test.c:85:8:85:23 | ... && ... | test.c:85:18:85:18 | y | != | 0 | 86 | 86 |
+| test.c:85:18:85:23 | ... != ... | test.c:85:18:85:18 | y | != | 0 | 86 | 86 |
+| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | != | 0 | 94 | 96 |
+| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 70 | 70 |
+| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 99 | 102 |
+| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 102 | 102 |
+| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 107 | 109 |
+| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 109 | 109 |
+| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 109 | 117 |
+| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 113 | 113 |
+| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | < | 10 | 102 | 102 |
+| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 70 | 70 |
+| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 107 | 109 |
+| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 109 | 109 |
+| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 109 | 117 |
+| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 113 | 113 |
+| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 109 | 109 |
+| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
+| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
+| test.c:109:9:109:23 | ... \|\| ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 |
+| test.c:109:19:109:23 | ... < ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 |
+| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 |
+| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
+| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 |
+| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 |
+| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 |
+| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
+| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
+| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
+| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
+| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
+| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 |
+| test.c:152:8:152:8 | p | test.c:152:8:152:8 | p | != | 0 | 152 | 154 |
+| test.c:158:8:158:9 | ! ... | test.c:158:8:158:9 | ! ... | != | 0 | 158 | 160 |
+| test.c:164:8:164:8 | s | test.c:164:8:164:8 | s | != | 0 | 164 | 166 |
+| test.c:170:8:170:9 | ! ... | test.c:170:8:170:9 | ! ... | != | 0 | 170 | 172 |
+| test.cpp:18:8:18:10 | call to get | test.cpp:18:8:18:10 | call to get | != | 0 | 19 | 19 |
+| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 30 | 30 |
+| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
+| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 30 | 30 |
+| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
+| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 0 | 62 | 64 |
+| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 1 | 65 | 66 |
+| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | < | 11 | 75 | 77 |
+| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | < | 21 | 78 | 79 |
+| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 0 | 75 | 77 |
+| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 11 | 78 | 79 |
+| test.cpp:93:6:93:6 | c | test.cpp:93:6:93:6 | c | != | 0 | 93 | 94 |
diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.ql b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.ql
index 94aaade03ed5..59f8a399c6d4 100644
--- a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.ql
+++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.ql
@@ -7,8 +7,9 @@
import cpp
import semmle.code.cpp.controlflow.Guards
-from GuardCondition guard, Expr left, Expr right, int k, int start, int end, string op
-where
+query predicate binary(
+ GuardCondition guard, Expr left, string op, Expr right, int k, int start, int end
+) {
exists(BasicBlock block |
guard.ensuresLt(left, right, k, block, true) and op = "<"
or
@@ -20,4 +21,18 @@ where
|
block.hasLocationInfo(_, start, _, end, _)
)
-select guard, left, op, right, k, start, end
+}
+
+query predicate unary(GuardCondition guard, Expr left, string op, int k, int start, int end) {
+ exists(BasicBlock block |
+ guard.ensuresLt(left, k, block, true) and op = "<"
+ or
+ guard.ensuresLt(left, k, block, false) and op = ">="
+ or
+ guard.ensuresEq(left, k, block, true) and op = "=="
+ or
+ guard.ensuresEq(left, k, block, false) and op = "!="
+ |
+ block.hasLocationInfo(_, start, _, end, _)
+ )
+}
diff --git a/cpp/ql/test/library-tests/controlflow/guards/test.c b/cpp/ql/test/library-tests/controlflow/guards/test.c
index 186244d4fca2..207e23baa0e3 100644
--- a/cpp/ql/test/library-tests/controlflow/guards/test.c
+++ b/cpp/ql/test/library-tests/controlflow/guards/test.c
@@ -147,3 +147,27 @@ void test5(int x) {
test3();
}
}
+
+void test6(char* p) {
+ if(p) {
+
+ }
+}
+
+void test7(char* p) {
+ if(!p) {
+
+ }
+}
+
+void test8(short s) {
+ if(s) {
+
+ }
+}
+
+void test9(short s) {
+ if(!s) {
+
+ }
+}
\ No newline at end of file
diff --git a/cpp/ql/test/library-tests/controlflow/guards/test.cpp b/cpp/ql/test/library-tests/controlflow/guards/test.cpp
index 3a60f5f026e7..84d02ca4efa5 100644
--- a/cpp/ql/test/library-tests/controlflow/guards/test.cpp
+++ b/cpp/ql/test/library-tests/controlflow/guards/test.cpp
@@ -85,4 +85,30 @@ void test_switches_default(int i) {
default:
use1(i);
}
-}
\ No newline at end of file
+}
+
+void use(...);
+
+void pointer_comparison(char* c) {
+ if(c) {
+ use(c);
+ }
+}
+
+void implicit_float_comparison(float f) {
+ if(f) {
+ use(f);
+ }
+}
+
+void explicit_float_comparison(float f) {
+ if(f != 0.0f) {
+ use(f);
+ }
+}
+
+void int_float_comparison(int i) {
+ if(i != 0.0f) {
+ use(i);
+ }
+}
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected
index e03ee68b8a35..e8afa785492f 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected
@@ -228,7 +228,6 @@ irFlow
| test.cpp:333:17:333:22 | call to source | test.cpp:337:10:337:18 | globalVar |
| test.cpp:333:17:333:22 | call to source | test.cpp:339:10:339:18 | globalVar |
| test.cpp:333:17:333:22 | call to source | test.cpp:343:10:343:18 | globalVar |
-| test.cpp:333:17:333:22 | call to source | test.cpp:349:10:349:18 | globalVar |
| test.cpp:347:17:347:22 | call to source | test.cpp:337:10:337:18 | globalVar |
| test.cpp:347:17:347:22 | call to source | test.cpp:339:10:339:18 | globalVar |
| test.cpp:347:17:347:22 | call to source | test.cpp:343:10:343:18 | globalVar |
@@ -260,7 +259,6 @@ irFlow
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:566:10:566:19 | * ... |
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:568:10:568:19 | * ... |
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:572:10:572:19 | * ... |
-| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:578:10:578:19 | * ... |
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:566:10:566:19 | * ... |
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:568:10:568:19 | * ... |
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:572:10:572:19 | * ... |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp
index af9e18034edd..c1c84c71e3bf 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp
@@ -346,7 +346,7 @@ namespace FlowThroughGlobals {
void taintAndCall() {
globalVar = source();
calledAfterTaint();
- sink(globalVar); // $ ast ir=333:17 ir=347:17
+ sink(globalVar); // $ ast ir
}
}
@@ -575,7 +575,7 @@ namespace IndirectFlowThroughGlobals {
void taintAndCall() {
globalInt = indirect_source();
calledAfterTaint();
- sink(*globalInt); // $ ir=562:17 ir=576:17 MISSING: ast=562:17 ast=576:17
+ sink(*globalInt); // $ ir MISSING: ast=562:17 ast=576:17
}
}
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp
index 7265cb175426..a39e06988065 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp
@@ -66,8 +66,8 @@ class insert_iterator_by_trait {
insert_iterator_by_trait operator++(int);
insert_iterator_by_trait &operator--();
insert_iterator_by_trait operator--(int);
- insert_iterator_by_trait operator*();
- insert_iterator_by_trait operator=(int x);
+ insert_iterator_by_trait& operator*();
+ insert_iterator_by_trait& operator=(int x);
};
template<>
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp
index 179c5eb6b199..c26eef5176ce 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp
@@ -389,7 +389,7 @@ void test_vector_output_iterator(int b) {
*i9 = source();
taint_vector_output_iterator(i9);
- sink(v9); // $ ast=330:10 MISSING: ir SPURIOUS: ast=389:8
+ sink(v9); // $ ast=330:10 ir SPURIOUS: ast=389:8
std::vector::iterator i10 = v10.begin();
vector_iterator_assign_wrapper(i10, 10);
@@ -440,14 +440,14 @@ void test_vector_inserter(char *source_string) {
std::vector out;
auto it = std::back_inserter(out);
*++it = std::string(source_string);
- sink(out); // $ ast MISSING: ir
+ sink(out); // $ ast,ir
}
{
std::vector out;
auto it = std::back_inserter(out);
*++it = source();
- sink(out); // $ ast MISSING: ir
+ sink(out); // $ ast,ir
}
}
diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
index 1f6a29b57ed6..d7b240c8949a 100644
--- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
+++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
@@ -12159,8 +12159,12 @@ ir.cpp:
# 1109| Type = [IntType] int
# 1110| [Destructor] void std::vector::~vector()
# 1110| :
+# 1110| [Destructor] void std::vector::~vector()
+# 1110| :
# 1110| [Destructor] void std::vector::~vector()
# 1110| :
+# 1110| [Destructor] void std::vector::~vector()
+# 1110| :
# 1110| [Destructor] void std::vector::~vector()
# 1110| :
# 1115| [ConstMemberFunction] std::vector::iterator std::vector::begin() const
@@ -19307,181 +19311,195 @@ ir.cpp:
# 2193| getQualifier(): [ThisExpr] this
# 2193| Type = [PointerType] ClassWithDestructor *
# 2193| ValueCategory = prvalue(load)
-# 2196| [GlobalVariable] bool initialization_with_destructor_bool
-# 2196| getInitializer(): [Initializer] initializer for initialization_with_destructor_bool
-# 2196| getExpr(): [Literal] 1
-# 2196| Type = [BoolType] bool
-# 2196| Value = [Literal] 1
-# 2196| ValueCategory = prvalue
-# 2198| [TopLevelFunction] void initialization_with_destructor(bool, char)
-# 2198| :
-# 2198| getParameter(0): [Parameter] b
-# 2198| Type = [BoolType] bool
-# 2198| getParameter(1): [Parameter] c
-# 2198| Type = [PlainCharType] char
-# 2198| getEntryPoint(): [BlockStmt] { ... }
-# 2199| getStmt(0): [IfStmt] if (...) ...
-# 2199| getInitialization(): [DeclStmt] declaration
-# 2199| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
-# 2199| Type = [Class] ClassWithDestructor
-# 2199| getVariable().getInitializer(): [Initializer] initializer for x
-# 2199| getExpr(): [ConstructorCall] call to ClassWithDestructor
-# 2199| Type = [VoidType] void
-# 2199| ValueCategory = prvalue
-# 2199| getCondition(): [VariableAccess] b
-# 2199| Type = [BoolType] bool
-# 2199| ValueCategory = prvalue(load)
-# 2200| getThen(): [ExprStmt] ExprStmt
-# 2200| getExpr(): [FunctionCall] call to set_x
-# 2200| Type = [VoidType] void
-# 2200| ValueCategory = prvalue
-# 2200| getQualifier(): [VariableAccess] x
-# 2200| Type = [Class] ClassWithDestructor
-# 2200| ValueCategory = lvalue
-# 2200| getArgument(0): [CharLiteral] 97
-# 2200| Type = [PlainCharType] char
-# 2200| Value = [CharLiteral] 97
-# 2200| ValueCategory = prvalue
-# 2200| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2200| Type = [VoidType] void
-# 2200| ValueCategory = prvalue
-# 2200| getQualifier(): [VariableAccess] x
+# 2194| [ConstMemberFunction,ConversionOperator] bool ClassWithDestructor::operator bool() const
+# 2194| :
+# 2197| [GlobalVariable] bool initialization_with_destructor_bool
+# 2197| getInitializer(): [Initializer] initializer for initialization_with_destructor_bool
+# 2197| getExpr(): [Literal] 1
+# 2197| Type = [BoolType] bool
+# 2197| Value = [Literal] 1
+# 2197| ValueCategory = prvalue
+# 2199| [TopLevelFunction] void initialization_with_destructor(bool, char)
+# 2199| :
+# 2199| getParameter(0): [Parameter] b
+# 2199| Type = [BoolType] bool
+# 2199| getParameter(1): [Parameter] c
+# 2199| Type = [PlainCharType] char
+# 2199| getEntryPoint(): [BlockStmt] { ... }
+# 2200| getStmt(0): [IfStmt] if (...) ...
+# 2200| getInitialization(): [DeclStmt] declaration
+# 2200| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 2200| Type = [Class] ClassWithDestructor
-# 2200| ValueCategory = lvalue
-# 2202| getStmt(1): [ConstexprIfStmt] if constexpr (...) ...
-# 2202| getInitialization(): [DeclStmt] declaration
-# 2202| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
-# 2202| Type = [Class] ClassWithDestructor
-# 2202| getVariable().getInitializer(): [Initializer] initializer for x
-# 2202| getExpr(): [ConstructorCall] call to ClassWithDestructor
-# 2202| Type = [VoidType] void
-# 2202| ValueCategory = prvalue
-# 2202| getCondition(): [VariableAccess] initialization_with_destructor_bool
-# 2202| Type = [BoolType] bool
-# 2202| Value = [VariableAccess] 1
-# 2202| ValueCategory = prvalue(load)
-# 2203| getThen(): [ExprStmt] ExprStmt
-# 2203| getExpr(): [FunctionCall] call to set_x
-# 2203| Type = [VoidType] void
-# 2203| ValueCategory = prvalue
-# 2203| getQualifier(): [VariableAccess] x
-# 2203| Type = [Class] ClassWithDestructor
-# 2203| ValueCategory = lvalue
-# 2203| getArgument(0): [CharLiteral] 97
-# 2203| Type = [PlainCharType] char
-# 2203| Value = [CharLiteral] 97
-# 2203| ValueCategory = prvalue
-# 2203| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2203| Type = [VoidType] void
-# 2203| ValueCategory = prvalue
-# 2203| getQualifier(): [VariableAccess] x
+# 2200| getVariable().getInitializer(): [Initializer] initializer for x
+# 2200| getExpr(): [ConstructorCall] call to ClassWithDestructor
+# 2200| Type = [VoidType] void
+# 2200| ValueCategory = prvalue
+# 2200| getCondition(): [VariableAccess] b
+# 2200| Type = [BoolType] bool
+# 2200| ValueCategory = prvalue(load)
+# 2201| getThen(): [ExprStmt] ExprStmt
+# 2201| getExpr(): [FunctionCall] call to set_x
+# 2201| Type = [VoidType] void
+# 2201| ValueCategory = prvalue
+# 2201| getQualifier(): [VariableAccess] x
+# 2201| Type = [Class] ClassWithDestructor
+# 2201| ValueCategory = lvalue
+# 2201| getArgument(0): [CharLiteral] 97
+# 2201| Type = [PlainCharType] char
+# 2201| Value = [CharLiteral] 97
+# 2201| ValueCategory = prvalue
+# 2201| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2201| Type = [VoidType] void
+# 2201| ValueCategory = prvalue
+# 2201| getQualifier(): [VariableAccess] x
+# 2201| Type = [Class] ClassWithDestructor
+# 2201| ValueCategory = lvalue
+# 2203| getStmt(1): [ConstexprIfStmt] if constexpr (...) ...
+# 2203| getInitialization(): [DeclStmt] declaration
+# 2203| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 2203| Type = [Class] ClassWithDestructor
-# 2203| ValueCategory = lvalue
-# 2205| getStmt(2): [SwitchStmt] switch (...) ...
-# 2205| getInitialization(): [DeclStmt] declaration
-# 2205| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
-# 2205| Type = [Class] ClassWithDestructor
-# 2205| getVariable().getInitializer(): [Initializer] initializer for x
-# 2205| getExpr(): [ConstructorCall] call to ClassWithDestructor
-# 2205| Type = [VoidType] void
-# 2205| ValueCategory = prvalue
-# 2205| getExpr(): [VariableAccess] c
-# 2205| Type = [PlainCharType] char
-# 2205| ValueCategory = prvalue(load)
-# 2205| getStmt(): [BlockStmt] { ... }
-# 2206| getStmt(0): [SwitchCase] case ...:
-# 2206| getExpr(): [CharLiteral] 97
-# 2206| Type = [PlainCharType] char
-# 2206| Value = [CharLiteral] 97
-# 2206| ValueCategory = prvalue
-# 2206| getExpr().getFullyConverted(): [CStyleCast] (int)...
-# 2206| Conversion = [IntegralConversion] integral conversion
-# 2206| Type = [IntType] int
-# 2206| Value = [CStyleCast] 97
-# 2206| ValueCategory = prvalue
-# 2207| getStmt(1): [ExprStmt] ExprStmt
-# 2207| getExpr(): [FunctionCall] call to set_x
-# 2207| Type = [VoidType] void
+# 2203| getVariable().getInitializer(): [Initializer] initializer for x
+# 2203| getExpr(): [ConstructorCall] call to ClassWithDestructor
+# 2203| Type = [VoidType] void
+# 2203| ValueCategory = prvalue
+# 2203| getCondition(): [VariableAccess] initialization_with_destructor_bool
+# 2203| Type = [BoolType] bool
+# 2203| Value = [VariableAccess] 1
+# 2203| ValueCategory = prvalue(load)
+# 2204| getThen(): [ExprStmt] ExprStmt
+# 2204| getExpr(): [FunctionCall] call to set_x
+# 2204| Type = [VoidType] void
+# 2204| ValueCategory = prvalue
+# 2204| getQualifier(): [VariableAccess] x
+# 2204| Type = [Class] ClassWithDestructor
+# 2204| ValueCategory = lvalue
+# 2204| getArgument(0): [CharLiteral] 97
+# 2204| Type = [PlainCharType] char
+# 2204| Value = [CharLiteral] 97
+# 2204| ValueCategory = prvalue
+# 2204| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2204| Type = [VoidType] void
+# 2204| ValueCategory = prvalue
+# 2204| getQualifier(): [VariableAccess] x
+# 2204| Type = [Class] ClassWithDestructor
+# 2204| ValueCategory = lvalue
+# 2206| getStmt(2): [SwitchStmt] switch (...) ...
+# 2206| getInitialization(): [DeclStmt] declaration
+# 2206| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
+# 2206| Type = [Class] ClassWithDestructor
+# 2206| getVariable().getInitializer(): [Initializer] initializer for x
+# 2206| getExpr(): [ConstructorCall] call to ClassWithDestructor
+# 2206| Type = [VoidType] void
+# 2206| ValueCategory = prvalue
+# 2206| getExpr(): [VariableAccess] c
+# 2206| Type = [PlainCharType] char
+# 2206| ValueCategory = prvalue(load)
+# 2206| getStmt(): [BlockStmt] { ... }
+# 2207| getStmt(0): [SwitchCase] case ...:
+# 2207| getExpr(): [CharLiteral] 97
+# 2207| Type = [PlainCharType] char
+# 2207| Value = [CharLiteral] 97
+# 2207| ValueCategory = prvalue
+# 2207| getExpr().getFullyConverted(): [CStyleCast] (int)...
+# 2207| Conversion = [IntegralConversion] integral conversion
+# 2207| Type = [IntType] int
+# 2207| Value = [CStyleCast] 97
# 2207| ValueCategory = prvalue
-# 2207| getQualifier(): [VariableAccess] x
-# 2207| Type = [Class] ClassWithDestructor
-# 2207| ValueCategory = lvalue
-# 2207| getArgument(0): [CharLiteral] 97
-# 2207| Type = [PlainCharType] char
-# 2207| Value = [CharLiteral] 97
-# 2207| ValueCategory = prvalue
-# 2208| getStmt(2): [BreakStmt] break;
-# 2209| getStmt(3): [SwitchCase] default:
-# 2210| getStmt(4): [ExprStmt] ExprStmt
-# 2210| getExpr(): [FunctionCall] call to set_x
-# 2210| Type = [VoidType] void
-# 2210| ValueCategory = prvalue
-# 2210| getQualifier(): [VariableAccess] x
-# 2210| Type = [Class] ClassWithDestructor
-# 2210| ValueCategory = lvalue
-# 2210| getArgument(0): [CharLiteral] 98
-# 2210| Type = [PlainCharType] char
-# 2210| Value = [CharLiteral] 98
-# 2210| ValueCategory = prvalue
-# 2211| getStmt(5): [BreakStmt] break;
-# 2212| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2212| Type = [VoidType] void
-# 2212| ValueCategory = prvalue
-# 2212| getQualifier(): [VariableAccess] x
-# 2212| Type = [Class] ClassWithDestructor
-# 2212| ValueCategory = lvalue
-# 2205| getExpr().getFullyConverted(): [CStyleCast] (int)...
-# 2205| Conversion = [IntegralConversion] integral conversion
-# 2205| Type = [IntType] int
-# 2205| ValueCategory = prvalue
-# 2212| getStmt(3): [LabelStmt] label ...:
-# 2214| getStmt(4): [DeclStmt] declaration
-# 2214| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
-# 2214| Type = [Class] ClassWithDestructor
-# 2214| getVariable().getInitializer(): [Initializer] initializer for x
-# 2214| getExpr(): [ConstructorCall] call to ClassWithDestructor
-# 2214| Type = [VoidType] void
-# 2214| ValueCategory = prvalue
-# 2215| getStmt(5): [RangeBasedForStmt] for(...:...) ...
-# 2215| getInitialization(): [DeclStmt] declaration
-# 2215| getDeclarationEntry(0): [VariableDeclarationEntry] definition of ys
-# 2215| Type = [ClassTemplateInstantiation,Struct] vector
-# 2215| getVariable().getInitializer(): [Initializer] initializer for ys
-# 2215| getExpr(): [ConstructorCall] call to vector
-# 2215| Type = [VoidType] void
-# 2215| ValueCategory = prvalue
-# 2215| getArgument(0): [VariableAccess] x
-# 2215| Type = [Class] ClassWithDestructor
-# 2215| ValueCategory = prvalue(load)
-# 2215| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2215| Type = [VoidType] void
-# 2215| ValueCategory = prvalue
-# 2215| getQualifier(): [ReuseExpr] reuse of temporary object
-# 2215| Type = [Class] ClassWithDestructor
-# 2215| ValueCategory = xvalue
-# 2215| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
-# 2215| Type = [Class] ClassWithDestructor
-# 2215| ValueCategory = lvalue
-# 2215| getChild(1): [DeclStmt] declaration
-# 2215| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
-# 2215| Type = [LValueReferenceType] vector &
+# 2208| getStmt(1): [ExprStmt] ExprStmt
+# 2208| getExpr(): [FunctionCall] call to set_x
+# 2208| Type = [VoidType] void
+# 2208| ValueCategory = prvalue
+# 2208| getQualifier(): [VariableAccess] x
+# 2208| Type = [Class] ClassWithDestructor
+# 2208| ValueCategory = lvalue
+# 2208| getArgument(0): [CharLiteral] 97
+# 2208| Type = [PlainCharType] char
+# 2208| Value = [CharLiteral] 97
+# 2208| ValueCategory = prvalue
+# 2209| getStmt(2): [BreakStmt] break;
+# 2213| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2213| Type = [VoidType] void
+# 2213| ValueCategory = prvalue
+# 2213| getQualifier(): [VariableAccess] x
+# 2213| Type = [Class] ClassWithDestructor
+# 2213| ValueCategory = lvalue
+# 2210| getStmt(3): [SwitchCase] default:
+# 2211| getStmt(4): [ExprStmt] ExprStmt
+# 2211| getExpr(): [FunctionCall] call to set_x
+# 2211| Type = [VoidType] void
+# 2211| ValueCategory = prvalue
+# 2211| getQualifier(): [VariableAccess] x
+# 2211| Type = [Class] ClassWithDestructor
+# 2211| ValueCategory = lvalue
+# 2211| getArgument(0): [CharLiteral] 98
+# 2211| Type = [PlainCharType] char
+# 2211| Value = [CharLiteral] 98
+# 2211| ValueCategory = prvalue
+# 2212| getStmt(5): [BreakStmt] break;
+# 2213| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2213| Type = [VoidType] void
+# 2213| ValueCategory = prvalue
+# 2213| getQualifier(): [VariableAccess] x
+# 2213| Type = [Class] ClassWithDestructor
+# 2213| ValueCategory = lvalue
+# 2213| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2213| Type = [VoidType] void
+# 2213| ValueCategory = prvalue
+# 2213| getQualifier(): [VariableAccess] x
+# 2213| Type = [Class] ClassWithDestructor
+# 2213| ValueCategory = lvalue
+# 2206| getExpr().getFullyConverted(): [CStyleCast] (int)...
+# 2206| Conversion = [IntegralConversion] integral conversion
+# 2206| Type = [IntType] int
+# 2206| ValueCategory = prvalue
+# 2213| getStmt(3): [LabelStmt] label ...:
+# 2215| getStmt(4): [DeclStmt] declaration
+# 2215| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
+# 2215| Type = [Class] ClassWithDestructor
+# 2215| getVariable().getInitializer(): [Initializer] initializer for x
+# 2215| getExpr(): [ConstructorCall] call to ClassWithDestructor
+# 2215| Type = [VoidType] void
+# 2215| ValueCategory = prvalue
+# 2216| getStmt(5): [RangeBasedForStmt] for(...:...) ...
+# 2216| getInitialization(): [DeclStmt] declaration
+# 2216| getDeclarationEntry(0): [VariableDeclarationEntry] definition of ys
+# 2216| Type = [ClassTemplateInstantiation,Struct] vector
+# 2216| getVariable().getInitializer(): [Initializer] initializer for ys
+# 2216| getExpr(): [ConstructorCall] call to vector
+# 2216| Type = [VoidType] void
+# 2216| ValueCategory = prvalue
+# 2216| getArgument(0): [VariableAccess] x
+# 2216| Type = [Class] ClassWithDestructor
+# 2216| ValueCategory = prvalue(load)
+# 2216| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2216| Type = [VoidType] void
+# 2216| ValueCategory = prvalue
+# 2216| getQualifier(): [ReuseExpr] reuse of temporary object
+# 2216| Type = [Class] ClassWithDestructor
+# 2216| ValueCategory = xvalue
+# 2216| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2216| Type = [Class] ClassWithDestructor
+# 2216| ValueCategory = lvalue
+# 2216| getChild(1): [DeclStmt] declaration
+# 2216| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
+# 2216| Type = [LValueReferenceType] vector &
#-----| getVariable().getInitializer(): [Initializer] initializer for (__range)
-# 2215| getExpr(): [VariableAccess] ys
-# 2215| Type = [ClassTemplateInstantiation,Struct] vector
-# 2215| ValueCategory = lvalue
-# 2215| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2215| Type = [LValueReferenceType] vector &
-# 2215| ValueCategory = prvalue
-# 2215| getBeginEndDeclaration(): [DeclStmt] declaration
-# 2215| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
-# 2215| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2216| getExpr(): [VariableAccess] ys
+# 2216| Type = [ClassTemplateInstantiation,Struct] vector
+# 2216| ValueCategory = lvalue
+# 2216| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2216| Type = [LValueReferenceType] vector &
+# 2216| ValueCategory = prvalue
+# 2216| getBeginEndDeclaration(): [DeclStmt] declaration
+# 2216| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
+# 2216| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
#-----| getVariable().getInitializer(): [Initializer] initializer for (__begin)
-# 2215| getExpr(): [FunctionCall] call to begin
-# 2215| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2215| ValueCategory = prvalue
-# 2215| getQualifier(): [VariableAccess] (__range)
-# 2215| Type = [LValueReferenceType] vector &
-# 2215| ValueCategory = prvalue(load)
+# 2216| getExpr(): [FunctionCall] call to begin
+# 2216| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2216| ValueCategory = prvalue
+# 2216| getQualifier(): [VariableAccess] (__range)
+# 2216| Type = [LValueReferenceType] vector &
+# 2216| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const vector)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const vector
@@ -19489,15 +19507,15 @@ ir.cpp:
#-----| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
#-----| Type = [ClassTemplateInstantiation,Struct] vector
#-----| ValueCategory = lvalue
-# 2215| getDeclarationEntry(1): [VariableDeclarationEntry] declaration of (__end)
-# 2215| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2216| getDeclarationEntry(1): [VariableDeclarationEntry] declaration of (__end)
+# 2216| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
#-----| getVariable().getInitializer(): [Initializer] initializer for (__end)
-# 2215| getExpr(): [FunctionCall] call to end
-# 2215| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2215| ValueCategory = prvalue
-# 2215| getQualifier(): [VariableAccess] (__range)
-# 2215| Type = [LValueReferenceType] vector &
-# 2215| ValueCategory = prvalue(load)
+# 2216| getExpr(): [FunctionCall] call to end
+# 2216| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2216| ValueCategory = prvalue
+# 2216| getQualifier(): [VariableAccess] (__range)
+# 2216| Type = [LValueReferenceType] vector &
+# 2216| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const vector)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const vector
@@ -19505,18 +19523,18 @@ ir.cpp:
#-----| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
#-----| Type = [ClassTemplateInstantiation,Struct] vector
#-----| ValueCategory = lvalue
-# 2215| getCondition(): [FunctionCall] call to operator!=
-# 2215| Type = [BoolType] bool
-# 2215| ValueCategory = prvalue
-# 2215| getQualifier(): [VariableAccess] (__begin)
-# 2215| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2215| ValueCategory = lvalue
-# 2215| getArgument(0): [ConstructorCall] call to iterator
-# 2215| Type = [VoidType] void
-# 2215| ValueCategory = prvalue
-# 2215| getArgument(0): [VariableAccess] (__end)
-# 2215| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2215| ValueCategory = lvalue
+# 2216| getCondition(): [FunctionCall] call to operator!=
+# 2216| Type = [BoolType] bool
+# 2216| ValueCategory = prvalue
+# 2216| getQualifier(): [VariableAccess] (__begin)
+# 2216| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2216| ValueCategory = lvalue
+# 2216| getArgument(0): [ConstructorCall] call to iterator
+# 2216| Type = [VoidType] void
+# 2216| ValueCategory = prvalue
+# 2216| getArgument(0): [VariableAccess] (__end)
+# 2216| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2216| ValueCategory = lvalue
#-----| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
#-----| Type = [LValueReferenceType] const iterator &
#-----| ValueCategory = prvalue
@@ -19531,95 +19549,95 @@ ir.cpp:
#-----| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
#-----| Type = [ClassTemplateInstantiation,Struct] iterator
#-----| ValueCategory = lvalue
-# 2215| getUpdate(): [FunctionCall] call to operator++
-# 2215| Type = [LValueReferenceType] iterator &
-# 2215| ValueCategory = prvalue
-# 2215| getQualifier(): [VariableAccess] (__begin)
-# 2215| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2215| ValueCategory = lvalue
-# 2215| getChild(5): [DeclStmt] declaration
-# 2215| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
-# 2215| Type = [Class] ClassWithDestructor
-# 2215| getVariable().getInitializer(): [Initializer] initializer for y
-# 2215| getExpr(): [OverloadedPointerDereferenceExpr] call to operator*
-# 2215| Type = [LValueReferenceType] ClassWithDestructor &
-# 2215| ValueCategory = prvalue
-# 2215| getQualifier(): [VariableAccess] (__begin)
-# 2215| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2215| ValueCategory = lvalue
+# 2216| getUpdate(): [FunctionCall] call to operator++
+# 2216| Type = [LValueReferenceType] iterator &
+# 2216| ValueCategory = prvalue
+# 2216| getQualifier(): [VariableAccess] (__begin)
+# 2216| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2216| ValueCategory = lvalue
+# 2216| getChild(5): [DeclStmt] declaration
+# 2216| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
+# 2216| Type = [Class] ClassWithDestructor
+# 2216| getVariable().getInitializer(): [Initializer] initializer for y
+# 2216| getExpr(): [OverloadedPointerDereferenceExpr] call to operator*
+# 2216| Type = [LValueReferenceType] ClassWithDestructor &
+# 2216| ValueCategory = prvalue
+# 2216| getQualifier(): [VariableAccess] (__begin)
+# 2216| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2216| ValueCategory = lvalue
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const iterator)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const iterator
#-----| ValueCategory = lvalue
-# 2215| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2215| Type = [Class] ClassWithDestructor
-# 2215| ValueCategory = prvalue(load)
-# 2216| getStmt(): [ExprStmt] ExprStmt
-# 2216| getExpr(): [FunctionCall] call to set_x
+# 2216| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2216| Type = [Class] ClassWithDestructor
+# 2216| ValueCategory = prvalue(load)
+# 2217| getStmt(): [ExprStmt] ExprStmt
+# 2217| getExpr(): [FunctionCall] call to set_x
+# 2217| Type = [VoidType] void
+# 2217| ValueCategory = prvalue
+# 2217| getQualifier(): [VariableAccess] y
+# 2217| Type = [Class] ClassWithDestructor
+# 2217| ValueCategory = lvalue
+# 2217| getArgument(0): [CharLiteral] 97
+# 2217| Type = [PlainCharType] char
+# 2217| Value = [CharLiteral] 97
+# 2217| ValueCategory = prvalue
+# 2216| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
+# 2216| Type = [VoidType] void
+# 2216| ValueCategory = prvalue
+# 2216| getQualifier(): [VariableAccess] ys
+# 2216| Type = [ClassTemplateInstantiation,Struct] vector
+# 2216| ValueCategory = lvalue
+# 2216| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2216| Type = [ClassTemplateInstantiation,Struct] iterator
+# 2216| ValueCategory = lvalue
+# 2216| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2216| Type = [VoidType] void
# 2216| ValueCategory = prvalue
# 2216| getQualifier(): [VariableAccess] y
# 2216| Type = [Class] ClassWithDestructor
# 2216| ValueCategory = lvalue
-# 2216| getArgument(0): [CharLiteral] 97
-# 2216| Type = [PlainCharType] char
-# 2216| Value = [CharLiteral] 97
-# 2216| ValueCategory = prvalue
-# 2215| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2215| Type = [VoidType] void
-# 2215| ValueCategory = prvalue
-# 2215| getQualifier(): [VariableAccess] y
-# 2215| Type = [Class] ClassWithDestructor
-# 2215| ValueCategory = lvalue
-# 2215| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
-# 2215| Type = [VoidType] void
-# 2215| ValueCategory = prvalue
-# 2215| getQualifier(): [VariableAccess] ys
-# 2215| Type = [ClassTemplateInstantiation,Struct] vector
-# 2215| ValueCategory = lvalue
-# 2215| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2215| Type = [ClassTemplateInstantiation,Struct] iterator
-# 2215| ValueCategory = lvalue
-# 2218| getStmt(6): [RangeBasedForStmt] for(...:...) ...
-# 2218| getInitialization(): [DeclStmt] declaration
-# 2218| getDeclarationEntry(0): [VariableDeclarationEntry] definition of ys
-# 2218| Type = [ClassTemplateInstantiation,Struct] vector
-# 2218| getVariable().getInitializer(): [Initializer] initializer for ys
-# 2218| getExpr(): [ConstructorCall] call to vector
-# 2218| Type = [VoidType] void
-# 2218| ValueCategory = prvalue
-# 2218| getArgument(0): [VariableAccess] x
-# 2218| Type = [Class] ClassWithDestructor
-# 2218| ValueCategory = prvalue(load)
-# 2218| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2218| Type = [VoidType] void
-# 2218| ValueCategory = prvalue
-# 2218| getQualifier(): [ReuseExpr] reuse of temporary object
-# 2218| Type = [Class] ClassWithDestructor
-# 2218| ValueCategory = xvalue
-# 2218| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
-# 2218| Type = [Class] ClassWithDestructor
-# 2218| ValueCategory = lvalue
-# 2218| getChild(1): [DeclStmt] declaration
-# 2218| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
-# 2218| Type = [LValueReferenceType] vector &
+# 2219| getStmt(6): [RangeBasedForStmt] for(...:...) ...
+# 2219| getInitialization(): [DeclStmt] declaration
+# 2219| getDeclarationEntry(0): [VariableDeclarationEntry] definition of ys
+# 2219| Type = [ClassTemplateInstantiation,Struct] vector
+# 2219| getVariable().getInitializer(): [Initializer] initializer for ys
+# 2219| getExpr(): [ConstructorCall] call to vector
+# 2219| Type = [VoidType] void
+# 2219| ValueCategory = prvalue
+# 2219| getArgument(0): [VariableAccess] x
+# 2219| Type = [Class] ClassWithDestructor
+# 2219| ValueCategory = prvalue(load)
+# 2219| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2219| Type = [VoidType] void
+# 2219| ValueCategory = prvalue
+# 2219| getQualifier(): [ReuseExpr] reuse of temporary object
+# 2219| Type = [Class] ClassWithDestructor
+# 2219| ValueCategory = xvalue
+# 2219| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2219| Type = [Class] ClassWithDestructor
+# 2219| ValueCategory = lvalue
+# 2219| getChild(1): [DeclStmt] declaration
+# 2219| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
+# 2219| Type = [LValueReferenceType] vector &
#-----| getVariable().getInitializer(): [Initializer] initializer for (__range)
-# 2218| getExpr(): [VariableAccess] ys
-# 2218| Type = [ClassTemplateInstantiation,Struct] vector
-# 2218| ValueCategory = lvalue
-# 2218| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2218| Type = [LValueReferenceType] vector &
-# 2218| ValueCategory = prvalue
-# 2218| getBeginEndDeclaration(): [DeclStmt] declaration
-# 2218| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
-# 2218| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2219| getExpr(): [VariableAccess] ys
+# 2219| Type = [ClassTemplateInstantiation,Struct] vector
+# 2219| ValueCategory = lvalue
+# 2219| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2219| Type = [LValueReferenceType] vector &
+# 2219| ValueCategory = prvalue
+# 2219| getBeginEndDeclaration(): [DeclStmt] declaration
+# 2219| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
+# 2219| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
#-----| getVariable().getInitializer(): [Initializer] initializer for (__begin)
-# 2218| getExpr(): [FunctionCall] call to begin
-# 2218| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2218| ValueCategory = prvalue
-# 2218| getQualifier(): [VariableAccess] (__range)
-# 2218| Type = [LValueReferenceType] vector &
-# 2218| ValueCategory = prvalue(load)
+# 2219| getExpr(): [FunctionCall] call to begin
+# 2219| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2219| ValueCategory = prvalue
+# 2219| getQualifier(): [VariableAccess] (__range)
+# 2219| Type = [LValueReferenceType] vector &
+# 2219| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const vector)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const vector
@@ -19627,15 +19645,15 @@ ir.cpp:
#-----| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
#-----| Type = [ClassTemplateInstantiation,Struct] vector
#-----| ValueCategory = lvalue
-# 2218| getDeclarationEntry(1): [VariableDeclarationEntry] declaration of (__end)
-# 2218| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2219| getDeclarationEntry(1): [VariableDeclarationEntry] declaration of (__end)
+# 2219| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
#-----| getVariable().getInitializer(): [Initializer] initializer for (__end)
-# 2218| getExpr(): [FunctionCall] call to end
-# 2218| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2218| ValueCategory = prvalue
-# 2218| getQualifier(): [VariableAccess] (__range)
-# 2218| Type = [LValueReferenceType] vector &
-# 2218| ValueCategory = prvalue(load)
+# 2219| getExpr(): [FunctionCall] call to end
+# 2219| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2219| ValueCategory = prvalue
+# 2219| getQualifier(): [VariableAccess] (__range)
+# 2219| Type = [LValueReferenceType] vector &
+# 2219| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const vector)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const vector
@@ -19643,18 +19661,18 @@ ir.cpp:
#-----| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
#-----| Type = [ClassTemplateInstantiation,Struct] vector
#-----| ValueCategory = lvalue
-# 2218| getCondition(): [FunctionCall] call to operator!=
-# 2218| Type = [BoolType] bool
-# 2218| ValueCategory = prvalue
-# 2218| getQualifier(): [VariableAccess] (__begin)
-# 2218| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2218| ValueCategory = lvalue
-# 2218| getArgument(0): [ConstructorCall] call to iterator
-# 2218| Type = [VoidType] void
-# 2218| ValueCategory = prvalue
-# 2218| getArgument(0): [VariableAccess] (__end)
-# 2218| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2218| ValueCategory = lvalue
+# 2219| getCondition(): [FunctionCall] call to operator!=
+# 2219| Type = [BoolType] bool
+# 2219| ValueCategory = prvalue
+# 2219| getQualifier(): [VariableAccess] (__begin)
+# 2219| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2219| ValueCategory = lvalue
+# 2219| getArgument(0): [ConstructorCall] call to iterator
+# 2219| Type = [VoidType] void
+# 2219| ValueCategory = prvalue
+# 2219| getArgument(0): [VariableAccess] (__end)
+# 2219| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2219| ValueCategory = lvalue
#-----| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
#-----| Type = [LValueReferenceType] const iterator &
#-----| ValueCategory = prvalue
@@ -19669,130 +19687,130 @@ ir.cpp:
#-----| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
#-----| Type = [ClassTemplateInstantiation,Struct] iterator
#-----| ValueCategory = lvalue
-# 2218| getUpdate(): [FunctionCall] call to operator++
-# 2218| Type = [LValueReferenceType] iterator &
-# 2218| ValueCategory = prvalue
-# 2218| getQualifier(): [VariableAccess] (__begin)
-# 2218| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2218| ValueCategory = lvalue
-# 2218| getChild(5): [DeclStmt] declaration
-# 2218| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
-# 2218| Type = [Class] ClassWithDestructor
-# 2218| getVariable().getInitializer(): [Initializer] initializer for y
-# 2218| getExpr(): [OverloadedPointerDereferenceExpr] call to operator*
-# 2218| Type = [LValueReferenceType] ClassWithDestructor &
-# 2218| ValueCategory = prvalue
-# 2218| getQualifier(): [VariableAccess] (__begin)
-# 2218| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2218| ValueCategory = lvalue
+# 2219| getUpdate(): [FunctionCall] call to operator++
+# 2219| Type = [LValueReferenceType] iterator &
+# 2219| ValueCategory = prvalue
+# 2219| getQualifier(): [VariableAccess] (__begin)
+# 2219| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2219| ValueCategory = lvalue
+# 2219| getChild(5): [DeclStmt] declaration
+# 2219| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
+# 2219| Type = [Class] ClassWithDestructor
+# 2219| getVariable().getInitializer(): [Initializer] initializer for y
+# 2219| getExpr(): [OverloadedPointerDereferenceExpr] call to operator*
+# 2219| Type = [LValueReferenceType] ClassWithDestructor &
+# 2219| ValueCategory = prvalue
+# 2219| getQualifier(): [VariableAccess] (__begin)
+# 2219| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2219| ValueCategory = lvalue
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const iterator)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const iterator
#-----| ValueCategory = lvalue
-# 2218| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2218| Type = [Class] ClassWithDestructor
-# 2218| ValueCategory = prvalue(load)
-# 2218| getStmt(): [BlockStmt] { ... }
-# 2219| getStmt(0): [ExprStmt] ExprStmt
-# 2219| getExpr(): [FunctionCall] call to set_x
-# 2219| Type = [VoidType] void
-# 2219| ValueCategory = prvalue
-# 2219| getQualifier(): [VariableAccess] y
+# 2219| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2219| Type = [Class] ClassWithDestructor
-# 2219| ValueCategory = lvalue
-# 2219| getArgument(0): [CharLiteral] 97
-# 2219| Type = [PlainCharType] char
-# 2219| Value = [CharLiteral] 97
-# 2219| ValueCategory = prvalue
-# 2220| getStmt(1): [IfStmt] if (...) ...
-# 2220| getCondition(): [EQExpr] ... == ...
-# 2220| Type = [BoolType] bool
+# 2219| ValueCategory = prvalue(load)
+# 2219| getStmt(): [BlockStmt] { ... }
+# 2220| getStmt(0): [ExprStmt] ExprStmt
+# 2220| getExpr(): [FunctionCall] call to set_x
+# 2220| Type = [VoidType] void
# 2220| ValueCategory = prvalue
-# 2220| getLeftOperand(): [FunctionCall] call to get_x
+# 2220| getQualifier(): [VariableAccess] y
+# 2220| Type = [Class] ClassWithDestructor
+# 2220| ValueCategory = lvalue
+# 2220| getArgument(0): [CharLiteral] 97
# 2220| Type = [PlainCharType] char
+# 2220| Value = [CharLiteral] 97
# 2220| ValueCategory = prvalue
-# 2220| getQualifier(): [VariableAccess] y
-# 2220| Type = [Class] ClassWithDestructor
-# 2220| ValueCategory = lvalue
-# 2220| getRightOperand(): [CharLiteral] 98
-# 2220| Type = [PlainCharType] char
-# 2220| Value = [CharLiteral] 98
-# 2220| ValueCategory = prvalue
-# 2220| getLeftOperand().getFullyConverted(): [CStyleCast] (int)...
-# 2220| Conversion = [IntegralConversion] integral conversion
-# 2220| Type = [IntType] int
-# 2220| ValueCategory = prvalue
-# 2220| getRightOperand().getFullyConverted(): [CStyleCast] (int)...
-# 2220| Conversion = [IntegralConversion] integral conversion
-# 2220| Type = [IntType] int
-# 2220| Value = [CStyleCast] 98
-# 2220| ValueCategory = prvalue
-# 2221| getThen(): [ReturnStmt] return ...
-# 2218| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2218| Type = [VoidType] void
-# 2218| ValueCategory = prvalue
-# 2218| getQualifier(): [VariableAccess] y
-# 2218| Type = [Class] ClassWithDestructor
-# 2218| ValueCategory = lvalue
-# 2218| getImplicitDestructorCall(1): [DestructorCall] call to ~vector
-# 2218| Type = [VoidType] void
-# 2218| ValueCategory = prvalue
-# 2218| getQualifier(): [VariableAccess] ys
-# 2218| Type = [ClassTemplateInstantiation,Struct] vector
-# 2218| ValueCategory = lvalue
-# 2233| getImplicitDestructorCall(2): [DestructorCall] call to ~ClassWithDestructor
-# 2233| Type = [VoidType] void
-# 2233| ValueCategory = prvalue
-# 2233| getQualifier(): [VariableAccess] x
-# 2233| Type = [Class] ClassWithDestructor
-# 2233| ValueCategory = lvalue
-# 2218| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2218| Type = [VoidType] void
-# 2218| ValueCategory = prvalue
-# 2218| getQualifier(): [VariableAccess] y
-# 2218| Type = [Class] ClassWithDestructor
-# 2218| ValueCategory = lvalue
-# 2218| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
-# 2218| Type = [VoidType] void
-# 2218| ValueCategory = prvalue
-# 2218| getQualifier(): [VariableAccess] ys
-# 2218| Type = [ClassTemplateInstantiation,Struct] vector
-# 2218| ValueCategory = lvalue
-# 2218| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2218| Type = [ClassTemplateInstantiation,Struct] iterator
-# 2218| ValueCategory = lvalue
-# 2224| getStmt(7): [RangeBasedForStmt] for(...:...) ...
-# 2224| getInitialization(): [DeclStmt] declaration
-# 2224| getDeclarationEntry(0): [VariableDeclarationEntry] definition of ys
-# 2224| Type = [ClassTemplateInstantiation,Struct] vector
-# 2224| getVariable().getInitializer(): [Initializer] initializer for ys
-# 2224| getExpr(): [ConstructorCall] call to vector
-# 2224| Type = [VoidType] void
-# 2224| ValueCategory = prvalue
-# 2224| getArgument(0): [Literal] 1
-# 2224| Type = [IntType] int
-# 2224| Value = [Literal] 1
-# 2224| ValueCategory = prvalue
-# 2224| getChild(1): [DeclStmt] declaration
-# 2224| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
-# 2224| Type = [LValueReferenceType] vector &
+# 2221| getStmt(1): [IfStmt] if (...) ...
+# 2221| getCondition(): [EQExpr] ... == ...
+# 2221| Type = [BoolType] bool
+# 2221| ValueCategory = prvalue
+# 2221| getLeftOperand(): [FunctionCall] call to get_x
+# 2221| Type = [PlainCharType] char
+# 2221| ValueCategory = prvalue
+# 2221| getQualifier(): [VariableAccess] y
+# 2221| Type = [Class] ClassWithDestructor
+# 2221| ValueCategory = lvalue
+# 2221| getRightOperand(): [CharLiteral] 98
+# 2221| Type = [PlainCharType] char
+# 2221| Value = [CharLiteral] 98
+# 2221| ValueCategory = prvalue
+# 2221| getLeftOperand().getFullyConverted(): [CStyleCast] (int)...
+# 2221| Conversion = [IntegralConversion] integral conversion
+# 2221| Type = [IntType] int
+# 2221| ValueCategory = prvalue
+# 2221| getRightOperand().getFullyConverted(): [CStyleCast] (int)...
+# 2221| Conversion = [IntegralConversion] integral conversion
+# 2221| Type = [IntType] int
+# 2221| Value = [CStyleCast] 98
+# 2221| ValueCategory = prvalue
+# 2222| getThen(): [ReturnStmt] return ...
+# 2219| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2219| Type = [VoidType] void
+# 2219| ValueCategory = prvalue
+# 2219| getQualifier(): [VariableAccess] y
+# 2219| Type = [Class] ClassWithDestructor
+# 2219| ValueCategory = lvalue
+# 2219| getImplicitDestructorCall(1): [DestructorCall] call to ~vector
+# 2219| Type = [VoidType] void
+# 2219| ValueCategory = prvalue
+# 2219| getQualifier(): [VariableAccess] ys
+# 2219| Type = [ClassTemplateInstantiation,Struct] vector
+# 2219| ValueCategory = lvalue
+# 2234| getImplicitDestructorCall(2): [DestructorCall] call to ~ClassWithDestructor
+# 2234| Type = [VoidType] void
+# 2234| ValueCategory = prvalue
+# 2234| getQualifier(): [VariableAccess] x
+# 2234| Type = [Class] ClassWithDestructor
+# 2234| ValueCategory = lvalue
+# 2219| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
+# 2219| Type = [VoidType] void
+# 2219| ValueCategory = prvalue
+# 2219| getQualifier(): [VariableAccess] ys
+# 2219| Type = [ClassTemplateInstantiation,Struct] vector
+# 2219| ValueCategory = lvalue
+# 2219| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2219| Type = [ClassTemplateInstantiation,Struct] iterator
+# 2219| ValueCategory = lvalue
+# 2219| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2219| Type = [VoidType] void
+# 2219| ValueCategory = prvalue
+# 2219| getQualifier(): [VariableAccess] y
+# 2219| Type = [Class] ClassWithDestructor
+# 2219| ValueCategory = lvalue
+# 2225| getStmt(7): [RangeBasedForStmt] for(...:...) ...
+# 2225| getInitialization(): [DeclStmt] declaration
+# 2225| getDeclarationEntry(0): [VariableDeclarationEntry] definition of ys
+# 2225| Type = [ClassTemplateInstantiation,Struct] vector
+# 2225| getVariable().getInitializer(): [Initializer] initializer for ys
+# 2225| getExpr(): [ConstructorCall] call to vector
+# 2225| Type = [VoidType] void
+# 2225| ValueCategory = prvalue
+# 2225| getArgument(0): [Literal] 1
+# 2225| Type = [IntType] int
+# 2225| Value = [Literal] 1
+# 2225| ValueCategory = prvalue
+# 2225| getChild(1): [DeclStmt] declaration
+# 2225| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
+# 2225| Type = [LValueReferenceType] vector &
#-----| getVariable().getInitializer(): [Initializer] initializer for (__range)
-# 2224| getExpr(): [VariableAccess] ys
-# 2224| Type = [ClassTemplateInstantiation,Struct] vector
-# 2224| ValueCategory = lvalue
-# 2224| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2224| Type = [LValueReferenceType] vector &
-# 2224| ValueCategory = prvalue
-# 2224| getBeginEndDeclaration(): [DeclStmt] declaration
-# 2224| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
-# 2224| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2225| getExpr(): [VariableAccess] ys
+# 2225| Type = [ClassTemplateInstantiation,Struct] vector
+# 2225| ValueCategory = lvalue
+# 2225| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2225| Type = [LValueReferenceType] vector &
+# 2225| ValueCategory = prvalue
+# 2225| getBeginEndDeclaration(): [DeclStmt] declaration
+# 2225| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
+# 2225| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
#-----| getVariable().getInitializer(): [Initializer] initializer for (__begin)
-# 2224| getExpr(): [FunctionCall] call to begin
-# 2224| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2224| ValueCategory = prvalue
-# 2224| getQualifier(): [VariableAccess] (__range)
-# 2224| Type = [LValueReferenceType] vector &
-# 2224| ValueCategory = prvalue(load)
+# 2225| getExpr(): [FunctionCall] call to begin
+# 2225| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2225| ValueCategory = prvalue
+# 2225| getQualifier(): [VariableAccess] (__range)
+# 2225| Type = [LValueReferenceType] vector &
+# 2225| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const vector)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const vector
@@ -19800,15 +19818,15 @@ ir.cpp:
#-----| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
#-----| Type = [ClassTemplateInstantiation,Struct] vector
#-----| ValueCategory = lvalue
-# 2224| getDeclarationEntry(1): [VariableDeclarationEntry] declaration of (__end)
-# 2224| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2225| getDeclarationEntry(1): [VariableDeclarationEntry] declaration of (__end)
+# 2225| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
#-----| getVariable().getInitializer(): [Initializer] initializer for (__end)
-# 2224| getExpr(): [FunctionCall] call to end
-# 2224| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2224| ValueCategory = prvalue
-# 2224| getQualifier(): [VariableAccess] (__range)
-# 2224| Type = [LValueReferenceType] vector &
-# 2224| ValueCategory = prvalue(load)
+# 2225| getExpr(): [FunctionCall] call to end
+# 2225| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2225| ValueCategory = prvalue
+# 2225| getQualifier(): [VariableAccess] (__range)
+# 2225| Type = [LValueReferenceType] vector &
+# 2225| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const vector)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const vector
@@ -19816,18 +19834,18 @@ ir.cpp:
#-----| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
#-----| Type = [ClassTemplateInstantiation,Struct] vector
#-----| ValueCategory = lvalue
-# 2224| getCondition(): [FunctionCall] call to operator!=
-# 2224| Type = [BoolType] bool
-# 2224| ValueCategory = prvalue
-# 2224| getQualifier(): [VariableAccess] (__begin)
-# 2224| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2224| ValueCategory = lvalue
-# 2224| getArgument(0): [ConstructorCall] call to iterator
-# 2224| Type = [VoidType] void
-# 2224| ValueCategory = prvalue
-# 2224| getArgument(0): [VariableAccess] (__end)
-# 2224| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2224| ValueCategory = lvalue
+# 2225| getCondition(): [FunctionCall] call to operator!=
+# 2225| Type = [BoolType] bool
+# 2225| ValueCategory = prvalue
+# 2225| getQualifier(): [VariableAccess] (__begin)
+# 2225| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2225| ValueCategory = lvalue
+# 2225| getArgument(0): [ConstructorCall] call to iterator
+# 2225| Type = [VoidType] void
+# 2225| ValueCategory = prvalue
+# 2225| getArgument(0): [VariableAccess] (__end)
+# 2225| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2225| ValueCategory = lvalue
#-----| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
#-----| Type = [LValueReferenceType] const iterator &
#-----| ValueCategory = prvalue
@@ -19842,103 +19860,103 @@ ir.cpp:
#-----| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
#-----| Type = [ClassTemplateInstantiation,Struct] iterator
#-----| ValueCategory = lvalue
-# 2224| getUpdate(): [FunctionCall] call to operator++
-# 2224| Type = [LValueReferenceType] iterator &
-# 2224| ValueCategory = prvalue
-# 2224| getQualifier(): [VariableAccess] (__begin)
-# 2224| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2224| ValueCategory = lvalue
-# 2224| getChild(5): [DeclStmt] declaration
-# 2224| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
-# 2224| Type = [IntType] int
-# 2224| getVariable().getInitializer(): [Initializer] initializer for y
-# 2224| getExpr(): [OverloadedPointerDereferenceExpr] call to operator*
-# 2224| Type = [LValueReferenceType] int &
-# 2224| ValueCategory = prvalue
-# 2224| getQualifier(): [VariableAccess] (__begin)
-# 2224| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2224| ValueCategory = lvalue
+# 2225| getUpdate(): [FunctionCall] call to operator++
+# 2225| Type = [LValueReferenceType] iterator &
+# 2225| ValueCategory = prvalue
+# 2225| getQualifier(): [VariableAccess] (__begin)
+# 2225| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2225| ValueCategory = lvalue
+# 2225| getChild(5): [DeclStmt] declaration
+# 2225| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
+# 2225| Type = [IntType] int
+# 2225| getVariable().getInitializer(): [Initializer] initializer for y
+# 2225| getExpr(): [OverloadedPointerDereferenceExpr] call to operator*
+# 2225| Type = [LValueReferenceType] int &
+# 2225| ValueCategory = prvalue
+# 2225| getQualifier(): [VariableAccess] (__begin)
+# 2225| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2225| ValueCategory = lvalue
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const iterator)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const iterator
#-----| ValueCategory = lvalue
-# 2224| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2224| Type = [IntType] int
-# 2224| ValueCategory = prvalue(load)
-# 2224| getStmt(): [BlockStmt] { ... }
-# 2225| getStmt(0): [IfStmt] if (...) ...
-# 2225| getCondition(): [EQExpr] ... == ...
-# 2225| Type = [BoolType] bool
-# 2225| ValueCategory = prvalue
-# 2225| getLeftOperand(): [VariableAccess] y
+# 2225| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2225| Type = [IntType] int
# 2225| ValueCategory = prvalue(load)
-# 2225| getRightOperand(): [Literal] 1
-# 2225| Type = [IntType] int
-# 2225| Value = [Literal] 1
+# 2225| getStmt(): [BlockStmt] { ... }
+# 2226| getStmt(0): [IfStmt] if (...) ...
+# 2226| getCondition(): [EQExpr] ... == ...
+# 2226| Type = [BoolType] bool
+# 2226| ValueCategory = prvalue
+# 2226| getLeftOperand(): [VariableAccess] y
+# 2226| Type = [IntType] int
+# 2226| ValueCategory = prvalue(load)
+# 2226| getRightOperand(): [Literal] 1
+# 2226| Type = [IntType] int
+# 2226| Value = [Literal] 1
+# 2226| ValueCategory = prvalue
+# 2227| getThen(): [ReturnStmt] return ...
+# 2225| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
+# 2225| Type = [VoidType] void
# 2225| ValueCategory = prvalue
-# 2226| getThen(): [ReturnStmt] return ...
-# 2224| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
-# 2224| Type = [VoidType] void
-# 2224| ValueCategory = prvalue
-# 2224| getQualifier(): [VariableAccess] ys
-# 2224| Type = [ClassTemplateInstantiation,Struct] vector
-# 2224| ValueCategory = lvalue
-# 2233| getImplicitDestructorCall(1): [DestructorCall] call to ~ClassWithDestructor
-# 2233| Type = [VoidType] void
-# 2233| ValueCategory = prvalue
-# 2233| getQualifier(): [VariableAccess] x
-# 2233| Type = [Class] ClassWithDestructor
-# 2233| ValueCategory = lvalue
-# 2224| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
-# 2224| Type = [VoidType] void
-# 2224| ValueCategory = prvalue
-# 2224| getQualifier(): [VariableAccess] ys
-# 2224| Type = [ClassTemplateInstantiation,Struct] vector
-# 2224| ValueCategory = lvalue
-# 2224| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2224| Type = [ClassTemplateInstantiation,Struct] iterator
-# 2224| ValueCategory = lvalue
-# 2229| getStmt(8): [RangeBasedForStmt] for(...:...) ...
-# 2229| getInitialization(): [DeclStmt] declaration
-# 2229| getDeclarationEntry(0): [VariableDeclarationEntry] definition of ys
-# 2229| Type = [ClassTemplateInstantiation,Struct] vector
-# 2229| getVariable().getInitializer(): [Initializer] initializer for ys
-# 2229| getExpr(): [ConstructorCall] call to vector
-# 2229| Type = [VoidType] void
-# 2229| ValueCategory = prvalue
-# 2229| getArgument(0): [VariableAccess] x
-# 2229| Type = [Class] ClassWithDestructor
-# 2229| ValueCategory = prvalue(load)
-# 2229| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2229| Type = [VoidType] void
-# 2229| ValueCategory = prvalue
-# 2229| getQualifier(): [ReuseExpr] reuse of temporary object
-# 2229| Type = [Class] ClassWithDestructor
-# 2229| ValueCategory = xvalue
-# 2229| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
-# 2229| Type = [Class] ClassWithDestructor
-# 2229| ValueCategory = lvalue
-# 2229| getChild(1): [DeclStmt] declaration
-# 2229| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
-# 2229| Type = [LValueReferenceType] vector &
+# 2225| getQualifier(): [VariableAccess] ys
+# 2225| Type = [ClassTemplateInstantiation,Struct] vector
+# 2225| ValueCategory = lvalue
+# 2234| getImplicitDestructorCall(1): [DestructorCall] call to ~ClassWithDestructor
+# 2234| Type = [VoidType] void
+# 2234| ValueCategory = prvalue
+# 2234| getQualifier(): [VariableAccess] x
+# 2234| Type = [Class] ClassWithDestructor
+# 2234| ValueCategory = lvalue
+# 2225| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
+# 2225| Type = [VoidType] void
+# 2225| ValueCategory = prvalue
+# 2225| getQualifier(): [VariableAccess] ys
+# 2225| Type = [ClassTemplateInstantiation,Struct] vector
+# 2225| ValueCategory = lvalue
+# 2225| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2225| Type = [ClassTemplateInstantiation,Struct] iterator
+# 2225| ValueCategory = lvalue
+# 2230| getStmt(8): [RangeBasedForStmt] for(...:...) ...
+# 2230| getInitialization(): [DeclStmt] declaration
+# 2230| getDeclarationEntry(0): [VariableDeclarationEntry] definition of ys
+# 2230| Type = [ClassTemplateInstantiation,Struct] vector
+# 2230| getVariable().getInitializer(): [Initializer] initializer for ys
+# 2230| getExpr(): [ConstructorCall] call to vector
+# 2230| Type = [VoidType] void
+# 2230| ValueCategory = prvalue
+# 2230| getArgument(0): [VariableAccess] x
+# 2230| Type = [Class] ClassWithDestructor
+# 2230| ValueCategory = prvalue(load)
+# 2230| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2230| Type = [VoidType] void
+# 2230| ValueCategory = prvalue
+# 2230| getQualifier(): [ReuseExpr] reuse of temporary object
+# 2230| Type = [Class] ClassWithDestructor
+# 2230| ValueCategory = xvalue
+# 2230| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2230| Type = [Class] ClassWithDestructor
+# 2230| ValueCategory = lvalue
+# 2230| getChild(1): [DeclStmt] declaration
+# 2230| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
+# 2230| Type = [LValueReferenceType] vector &
#-----| getVariable().getInitializer(): [Initializer] initializer for (__range)
-# 2229| getExpr(): [VariableAccess] ys
-# 2229| Type = [ClassTemplateInstantiation,Struct] vector
-# 2229| ValueCategory = lvalue
-# 2229| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2229| Type = [LValueReferenceType] vector &
-# 2229| ValueCategory = prvalue
-# 2229| getBeginEndDeclaration(): [DeclStmt] declaration
-# 2229| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
-# 2229| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2230| getExpr(): [VariableAccess] ys
+# 2230| Type = [ClassTemplateInstantiation,Struct] vector
+# 2230| ValueCategory = lvalue
+# 2230| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2230| Type = [LValueReferenceType] vector &
+# 2230| ValueCategory = prvalue
+# 2230| getBeginEndDeclaration(): [DeclStmt] declaration
+# 2230| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
+# 2230| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
#-----| getVariable().getInitializer(): [Initializer] initializer for (__begin)
-# 2229| getExpr(): [FunctionCall] call to begin
-# 2229| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2229| ValueCategory = prvalue
-# 2229| getQualifier(): [VariableAccess] (__range)
-# 2229| Type = [LValueReferenceType] vector &
-# 2229| ValueCategory = prvalue(load)
+# 2230| getExpr(): [FunctionCall] call to begin
+# 2230| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2230| ValueCategory = prvalue
+# 2230| getQualifier(): [VariableAccess] (__range)
+# 2230| Type = [LValueReferenceType] vector &
+# 2230| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const vector)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const vector
@@ -19946,15 +19964,15 @@ ir.cpp:
#-----| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
#-----| Type = [ClassTemplateInstantiation,Struct] vector
#-----| ValueCategory = lvalue
-# 2229| getDeclarationEntry(1): [VariableDeclarationEntry] declaration of (__end)
-# 2229| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2230| getDeclarationEntry(1): [VariableDeclarationEntry] declaration of (__end)
+# 2230| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
#-----| getVariable().getInitializer(): [Initializer] initializer for (__end)
-# 2229| getExpr(): [FunctionCall] call to end
-# 2229| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2229| ValueCategory = prvalue
-# 2229| getQualifier(): [VariableAccess] (__range)
-# 2229| Type = [LValueReferenceType] vector &
-# 2229| ValueCategory = prvalue(load)
+# 2230| getExpr(): [FunctionCall] call to end
+# 2230| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2230| ValueCategory = prvalue
+# 2230| getQualifier(): [VariableAccess] (__range)
+# 2230| Type = [LValueReferenceType] vector &
+# 2230| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const vector)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const vector
@@ -19962,18 +19980,18 @@ ir.cpp:
#-----| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
#-----| Type = [ClassTemplateInstantiation,Struct] vector
#-----| ValueCategory = lvalue
-# 2229| getCondition(): [FunctionCall] call to operator!=
-# 2229| Type = [BoolType] bool
-# 2229| ValueCategory = prvalue
-# 2229| getQualifier(): [VariableAccess] (__begin)
-# 2229| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2229| ValueCategory = lvalue
-# 2229| getArgument(0): [ConstructorCall] call to iterator
-# 2229| Type = [VoidType] void
-# 2229| ValueCategory = prvalue
-# 2229| getArgument(0): [VariableAccess] (__end)
-# 2229| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2229| ValueCategory = lvalue
+# 2230| getCondition(): [FunctionCall] call to operator!=
+# 2230| Type = [BoolType] bool
+# 2230| ValueCategory = prvalue
+# 2230| getQualifier(): [VariableAccess] (__begin)
+# 2230| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2230| ValueCategory = lvalue
+# 2230| getArgument(0): [ConstructorCall] call to iterator
+# 2230| Type = [VoidType] void
+# 2230| ValueCategory = prvalue
+# 2230| getArgument(0): [VariableAccess] (__end)
+# 2230| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2230| ValueCategory = lvalue
#-----| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
#-----| Type = [LValueReferenceType] const iterator &
#-----| ValueCategory = prvalue
@@ -19988,584 +20006,584 @@ ir.cpp:
#-----| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
#-----| Type = [ClassTemplateInstantiation,Struct] iterator
#-----| ValueCategory = lvalue
-# 2229| getUpdate(): [FunctionCall] call to operator++
-# 2229| Type = [LValueReferenceType] iterator &
-# 2229| ValueCategory = prvalue
-# 2229| getQualifier(): [VariableAccess] (__begin)
-# 2229| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2229| ValueCategory = lvalue
-# 2229| getChild(5): [DeclStmt] declaration
-# 2229| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
-# 2229| Type = [Class] ClassWithDestructor
-# 2229| getVariable().getInitializer(): [Initializer] initializer for y
-# 2229| getExpr(): [OverloadedPointerDereferenceExpr] call to operator*
-# 2229| Type = [LValueReferenceType] ClassWithDestructor &
-# 2229| ValueCategory = prvalue
-# 2229| getQualifier(): [VariableAccess] (__begin)
-# 2229| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2229| ValueCategory = lvalue
+# 2230| getUpdate(): [FunctionCall] call to operator++
+# 2230| Type = [LValueReferenceType] iterator &
+# 2230| ValueCategory = prvalue
+# 2230| getQualifier(): [VariableAccess] (__begin)
+# 2230| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2230| ValueCategory = lvalue
+# 2230| getChild(5): [DeclStmt] declaration
+# 2230| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
+# 2230| Type = [Class] ClassWithDestructor
+# 2230| getVariable().getInitializer(): [Initializer] initializer for y
+# 2230| getExpr(): [OverloadedPointerDereferenceExpr] call to operator*
+# 2230| Type = [LValueReferenceType] ClassWithDestructor &
+# 2230| ValueCategory = prvalue
+# 2230| getQualifier(): [VariableAccess] (__begin)
+# 2230| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2230| ValueCategory = lvalue
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const iterator)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const iterator
#-----| ValueCategory = lvalue
-# 2229| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2229| Type = [Class] ClassWithDestructor
-# 2229| ValueCategory = prvalue(load)
-# 2229| getStmt(): [BlockStmt] { ... }
-# 2230| getStmt(0): [DeclStmt] declaration
-# 2230| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z1
-# 2230| Type = [Class] ClassWithDestructor
-# 2230| getVariable().getInitializer(): [Initializer] initializer for z1
-# 2230| getExpr(): [ConstructorCall] call to ClassWithDestructor
-# 2230| Type = [VoidType] void
-# 2230| ValueCategory = prvalue
-# 2231| getStmt(1): [DeclStmt] declaration
-# 2231| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z2
+# 2230| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2230| Type = [Class] ClassWithDestructor
+# 2230| ValueCategory = prvalue(load)
+# 2230| getStmt(): [BlockStmt] { ... }
+# 2231| getStmt(0): [DeclStmt] declaration
+# 2231| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z1
# 2231| Type = [Class] ClassWithDestructor
-# 2231| getVariable().getInitializer(): [Initializer] initializer for z2
+# 2231| getVariable().getInitializer(): [Initializer] initializer for z1
# 2231| getExpr(): [ConstructorCall] call to ClassWithDestructor
# 2231| Type = [VoidType] void
# 2231| ValueCategory = prvalue
-# 2232| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2232| Type = [VoidType] void
-# 2232| ValueCategory = prvalue
-# 2232| getQualifier(): [VariableAccess] z2
+# 2232| getStmt(1): [DeclStmt] declaration
+# 2232| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z2
# 2232| Type = [Class] ClassWithDestructor
-# 2232| ValueCategory = lvalue
-# 2232| getImplicitDestructorCall(1): [DestructorCall] call to ~ClassWithDestructor
-# 2232| Type = [VoidType] void
-# 2232| ValueCategory = prvalue
-# 2232| getQualifier(): [VariableAccess] z1
-# 2232| Type = [Class] ClassWithDestructor
-# 2232| ValueCategory = lvalue
-# 2229| getImplicitDestructorCall(2): [DestructorCall] call to ~ClassWithDestructor
-# 2229| Type = [VoidType] void
-# 2229| ValueCategory = prvalue
-# 2229| getQualifier(): [VariableAccess] y
-# 2229| Type = [Class] ClassWithDestructor
-# 2229| ValueCategory = lvalue
-# 2229| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
-# 2229| Type = [VoidType] void
-# 2229| ValueCategory = prvalue
-# 2229| getQualifier(): [VariableAccess] ys
-# 2229| Type = [ClassTemplateInstantiation,Struct] vector
-# 2229| ValueCategory = lvalue
-# 2229| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2229| Type = [ClassTemplateInstantiation,Struct] iterator
-# 2229| ValueCategory = lvalue
-# 2233| getStmt(9): [ReturnStmt] return ...
-# 2233| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2233| Type = [VoidType] void
-# 2233| ValueCategory = prvalue
-# 2233| getQualifier(): [VariableAccess] x
-# 2233| Type = [Class] ClassWithDestructor
-# 2233| ValueCategory = lvalue
-# 2235| [TopLevelFunction] void static_variable_with_destructor_1()
-# 2235| :
-# 2235| getEntryPoint(): [BlockStmt] { ... }
-# 2236| getStmt(0): [DeclStmt] declaration
-# 2236| getDeclarationEntry(0): [VariableDeclarationEntry] definition of a
-# 2236| Type = [Class] ClassWithDestructor
-# 2236| getVariable().getInitializer(): [Initializer] initializer for a
-# 2236| getExpr(): [ConstructorCall] call to ClassWithDestructor
-# 2236| Type = [VoidType] void
-# 2236| ValueCategory = prvalue
-# 2237| getStmt(1): [DeclStmt] declaration
-# 2237| getDeclarationEntry(0): [VariableDeclarationEntry] definition of b
+# 2232| getVariable().getInitializer(): [Initializer] initializer for z2
+# 2232| getExpr(): [ConstructorCall] call to ClassWithDestructor
+# 2232| Type = [VoidType] void
+# 2232| ValueCategory = prvalue
+# 2233| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2233| Type = [VoidType] void
+# 2233| ValueCategory = prvalue
+# 2233| getQualifier(): [VariableAccess] z2
+# 2233| Type = [Class] ClassWithDestructor
+# 2233| ValueCategory = lvalue
+# 2233| getImplicitDestructorCall(1): [DestructorCall] call to ~ClassWithDestructor
+# 2233| Type = [VoidType] void
+# 2233| ValueCategory = prvalue
+# 2233| getQualifier(): [VariableAccess] z1
+# 2233| Type = [Class] ClassWithDestructor
+# 2233| ValueCategory = lvalue
+# 2230| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
+# 2230| Type = [VoidType] void
+# 2230| ValueCategory = prvalue
+# 2230| getQualifier(): [VariableAccess] ys
+# 2230| Type = [ClassTemplateInstantiation,Struct] vector
+# 2230| ValueCategory = lvalue
+# 2230| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2230| Type = [ClassTemplateInstantiation,Struct] iterator
+# 2230| ValueCategory = lvalue
+# 2230| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2230| Type = [VoidType] void
+# 2230| ValueCategory = prvalue
+# 2230| getQualifier(): [VariableAccess] y
+# 2230| Type = [Class] ClassWithDestructor
+# 2230| ValueCategory = lvalue
+# 2234| getStmt(9): [ReturnStmt] return ...
+# 2234| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2234| Type = [VoidType] void
+# 2234| ValueCategory = prvalue
+# 2234| getQualifier(): [VariableAccess] x
+# 2234| Type = [Class] ClassWithDestructor
+# 2234| ValueCategory = lvalue
+# 2236| [TopLevelFunction] void static_variable_with_destructor_1()
+# 2236| :
+# 2236| getEntryPoint(): [BlockStmt] { ... }
+# 2237| getStmt(0): [DeclStmt] declaration
+# 2237| getDeclarationEntry(0): [VariableDeclarationEntry] definition of a
# 2237| Type = [Class] ClassWithDestructor
+# 2237| getVariable().getInitializer(): [Initializer] initializer for a
+# 2237| getExpr(): [ConstructorCall] call to ClassWithDestructor
+# 2237| Type = [VoidType] void
+# 2237| ValueCategory = prvalue
+# 2238| getStmt(1): [DeclStmt] declaration
+# 2238| getDeclarationEntry(0): [VariableDeclarationEntry] definition of b
+# 2238| Type = [Class] ClassWithDestructor
#-----| getVariable().getInitializer(): [Initializer] initializer for b
#-----| getExpr(): [ConstructorCall] call to ClassWithDestructor
#-----| Type = [VoidType] void
#-----| ValueCategory = prvalue
-# 2238| getStmt(2): [ReturnStmt] return ...
-# 2238| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2238| Type = [VoidType] void
-# 2238| ValueCategory = prvalue
-# 2238| getQualifier(): [VariableAccess] a
-# 2238| Type = [Class] ClassWithDestructor
-# 2238| ValueCategory = lvalue
-# 2240| [TopLevelFunction] void static_variable_with_destructor_2()
-# 2240| :
-# 2240| getEntryPoint(): [BlockStmt] { ... }
-# 2241| getStmt(0): [DeclStmt] declaration
-# 2241| getDeclarationEntry(0): [VariableDeclarationEntry] definition of a
-# 2241| Type = [Class] ClassWithDestructor
+# 2239| getStmt(2): [ReturnStmt] return ...
+# 2239| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2239| Type = [VoidType] void
+# 2239| ValueCategory = prvalue
+# 2239| getQualifier(): [VariableAccess] a
+# 2239| Type = [Class] ClassWithDestructor
+# 2239| ValueCategory = lvalue
+# 2241| [TopLevelFunction] void static_variable_with_destructor_2()
+# 2241| :
+# 2241| getEntryPoint(): [BlockStmt] { ... }
+# 2242| getStmt(0): [DeclStmt] declaration
+# 2242| getDeclarationEntry(0): [VariableDeclarationEntry] definition of a
+# 2242| Type = [Class] ClassWithDestructor
#-----| getVariable().getInitializer(): [Initializer] initializer for a
#-----| getExpr(): [ConstructorCall] call to ClassWithDestructor
#-----| Type = [VoidType] void
#-----| ValueCategory = prvalue
-# 2242| getStmt(1): [DeclStmt] declaration
-# 2242| getDeclarationEntry(0): [VariableDeclarationEntry] definition of b
-# 2242| Type = [Class] ClassWithDestructor
-# 2242| getVariable().getInitializer(): [Initializer] initializer for b
-# 2242| getExpr(): [ConstructorCall] call to ClassWithDestructor
-# 2242| Type = [VoidType] void
-# 2242| ValueCategory = prvalue
-# 2243| getStmt(2): [ReturnStmt] return ...
-# 2243| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2243| Type = [VoidType] void
-# 2243| ValueCategory = prvalue
-# 2243| getQualifier(): [VariableAccess] b
-# 2243| Type = [Class] ClassWithDestructor
-# 2243| ValueCategory = lvalue
-# 2245| [TopLevelFunction] void static_variable_with_destructor_3()
-# 2245| :
-# 2245| getEntryPoint(): [BlockStmt] { ... }
-# 2246| getStmt(0): [DeclStmt] declaration
-# 2246| getDeclarationEntry(0): [VariableDeclarationEntry] definition of a
-# 2246| Type = [Class] ClassWithDestructor
-# 2246| getVariable().getInitializer(): [Initializer] initializer for a
-# 2246| getExpr(): [ConstructorCall] call to ClassWithDestructor
-# 2246| Type = [VoidType] void
-# 2246| ValueCategory = prvalue
-# 2247| getStmt(1): [DeclStmt] declaration
-# 2247| getDeclarationEntry(0): [VariableDeclarationEntry] definition of b
+# 2243| getStmt(1): [DeclStmt] declaration
+# 2243| getDeclarationEntry(0): [VariableDeclarationEntry] definition of b
+# 2243| Type = [Class] ClassWithDestructor
+# 2243| getVariable().getInitializer(): [Initializer] initializer for b
+# 2243| getExpr(): [ConstructorCall] call to ClassWithDestructor
+# 2243| Type = [VoidType] void
+# 2243| ValueCategory = prvalue
+# 2244| getStmt(2): [ReturnStmt] return ...
+# 2244| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2244| Type = [VoidType] void
+# 2244| ValueCategory = prvalue
+# 2244| getQualifier(): [VariableAccess] b
+# 2244| Type = [Class] ClassWithDestructor
+# 2244| ValueCategory = lvalue
+# 2246| [TopLevelFunction] void static_variable_with_destructor_3()
+# 2246| :
+# 2246| getEntryPoint(): [BlockStmt] { ... }
+# 2247| getStmt(0): [DeclStmt] declaration
+# 2247| getDeclarationEntry(0): [VariableDeclarationEntry] definition of a
# 2247| Type = [Class] ClassWithDestructor
-# 2247| getVariable().getInitializer(): [Initializer] initializer for b
+# 2247| getVariable().getInitializer(): [Initializer] initializer for a
# 2247| getExpr(): [ConstructorCall] call to ClassWithDestructor
# 2247| Type = [VoidType] void
# 2247| ValueCategory = prvalue
-# 2248| getStmt(2): [DeclStmt] declaration
-# 2248| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
+# 2248| getStmt(1): [DeclStmt] declaration
+# 2248| getDeclarationEntry(0): [VariableDeclarationEntry] definition of b
# 2248| Type = [Class] ClassWithDestructor
+# 2248| getVariable().getInitializer(): [Initializer] initializer for b
+# 2248| getExpr(): [ConstructorCall] call to ClassWithDestructor
+# 2248| Type = [VoidType] void
+# 2248| ValueCategory = prvalue
+# 2249| getStmt(2): [DeclStmt] declaration
+# 2249| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
+# 2249| Type = [Class] ClassWithDestructor
#-----| getVariable().getInitializer(): [Initializer] initializer for c
#-----| getExpr(): [ConstructorCall] call to ClassWithDestructor
#-----| Type = [VoidType] void
#-----| ValueCategory = prvalue
-# 2249| getStmt(3): [ReturnStmt] return ...
-# 2249| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2249| Type = [VoidType] void
-# 2249| ValueCategory = prvalue
-# 2249| getQualifier(): [VariableAccess] b
-# 2249| Type = [Class] ClassWithDestructor
-# 2249| ValueCategory = lvalue
-# 2249| getImplicitDestructorCall(1): [DestructorCall] call to ~ClassWithDestructor
-# 2249| Type = [VoidType] void
-# 2249| ValueCategory = prvalue
-# 2249| getQualifier(): [VariableAccess] a
-# 2249| Type = [Class] ClassWithDestructor
-# 2249| ValueCategory = lvalue
-# 2251| [GlobalVariable] ClassWithDestructor global_class_with_destructor
-# 2251| getInitializer(): [Initializer] initializer for global_class_with_destructor
-# 2251| getExpr(): [ConstructorCall] call to ClassWithDestructor
-# 2251| Type = [VoidType] void
-# 2251| ValueCategory = prvalue
-# 2255| [FunctionTemplateInstantiation,TopLevelFunction] ClassWithDestructor& vacuous_destructor_call::get(ClassWithDestructor&)
-# 2255| :
-# 2255| getParameter(0): [Parameter] t
-# 2255| Type = [LValueReferenceType] ClassWithDestructor &
-# 2255| getEntryPoint(): [BlockStmt] { ... }
-# 2255| getStmt(0): [ReturnStmt] return ...
-# 2255| getExpr(): [VariableAccess] t
-# 2255| Type = [LValueReferenceType] ClassWithDestructor &
-# 2255| ValueCategory = prvalue(load)
-# 2255| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2255| Type = [LValueReferenceType] ClassWithDestructor &
-# 2255| ValueCategory = prvalue
-# 2255| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
-# 2255| Type = [Class] ClassWithDestructor
-# 2255| ValueCategory = lvalue
-# 2255| [TemplateFunction,TopLevelFunction] T& vacuous_destructor_call::get(T&)
-# 2255| :
-# 2255| getParameter(0): [Parameter] t
-# 2255| Type = [LValueReferenceType] T &
-# 2255| getEntryPoint(): [BlockStmt] { ... }
-# 2255| getStmt(0): [ReturnStmt] return ...
-# 2255| getExpr(): [VariableAccess] t
-# 2255| Type = [LValueReferenceType] T &
-# 2255| ValueCategory = prvalue(load)
-# 2255| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2255| Type = [TemplateParameter] T
-# 2255| ValueCategory = lvalue
-# 2255| [FunctionTemplateInstantiation,TopLevelFunction] int& vacuous_destructor_call::get(int&)
-# 2255| :
-# 2255| getParameter(0): [Parameter] t
-# 2255| Type = [LValueReferenceType] int &
-# 2255| getEntryPoint(): [BlockStmt] { ... }
-# 2255| getStmt(0): [ReturnStmt] return ...
-# 2255| getExpr(): [VariableAccess] t
-# 2255| Type = [LValueReferenceType] int &
-# 2255| ValueCategory = prvalue(load)
-# 2255| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2255| Type = [LValueReferenceType] int &
-# 2255| ValueCategory = prvalue
-# 2255| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
-# 2255| Type = [IntType] int
-# 2255| ValueCategory = lvalue
-# 2258| [FunctionTemplateInstantiation,TopLevelFunction] void vacuous_destructor_call::call_destructor(ClassWithDestructor&)
-# 2258| :
-# 2258| getParameter(0): [Parameter] t
-# 2258| Type = [LValueReferenceType] ClassWithDestructor &
-# 2258| getEntryPoint(): [BlockStmt] { ... }
-# 2259| getStmt(0): [ExprStmt] ExprStmt
-# 2259| getExpr(): [DestructorCall] call to ~ClassWithDestructor
-# 2259| Type = [VoidType] void
-# 2259| ValueCategory = prvalue
-# 2259| getQualifier(): [FunctionCall] call to get
-# 2259| Type = [LValueReferenceType] ClassWithDestructor &
-# 2259| ValueCategory = prvalue
-# 2259| getArgument(0): [VariableAccess] t
-# 2259| Type = [LValueReferenceType] ClassWithDestructor &
-# 2259| ValueCategory = prvalue(load)
-# 2259| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2259| Type = [LValueReferenceType] ClassWithDestructor &
-# 2259| ValueCategory = prvalue
-# 2259| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
-# 2259| Type = [Class] ClassWithDestructor
-# 2259| ValueCategory = lvalue
-# 2259| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2259| Type = [Class] ClassWithDestructor
-# 2259| ValueCategory = lvalue
-# 2260| getStmt(1): [ReturnStmt] return ...
-# 2258| [TemplateFunction,TopLevelFunction] void vacuous_destructor_call::call_destructor(T&)
-# 2258| :
-# 2258| getParameter(0): [Parameter] t
-# 2258| Type = [LValueReferenceType] T &
-# 2258| getEntryPoint(): [BlockStmt] { ... }
-# 2259| getStmt(0): [ExprStmt] ExprStmt
-# 2259| getExpr(): [ExprCall] call to expression
-# 2259| Type = [UnknownType] unknown
-# 2259| ValueCategory = prvalue
-# 2259| getExpr(): [Literal] Unknown literal
-# 2259| Type = [UnknownType] unknown
-# 2259| ValueCategory = prvalue
-# 2259| getChild(-1): [ExprCall] call to expression
-# 2259| Type = [UnknownType] unknown
-# 2259| ValueCategory = prvalue
-# 2259| getExpr(): [Literal] Unknown literal
-# 2259| Type = [UnknownType] unknown
-# 2259| ValueCategory = prvalue
-# 2259| getArgument(0): [VariableAccess] t
-# 2259| Type = [LValueReferenceType] T &
-# 2259| ValueCategory = prvalue(load)
-# 2259| getArgument(0).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2259| Type = [TemplateParameter] T
-# 2259| ValueCategory = lvalue
-# 2260| getStmt(1): [ReturnStmt] return ...
-# 2258| [FunctionTemplateInstantiation,TopLevelFunction] void vacuous_destructor_call::call_destructor(int&)
-# 2258| :
-# 2258| getParameter(0): [Parameter] t
-# 2258| Type = [LValueReferenceType] int &
-# 2258| getEntryPoint(): [BlockStmt] { ... }
-# 2259| getStmt(0): [ExprStmt] ExprStmt
-# 2259| getExpr(): [VacuousDestructorCall] (vacuous destructor call)
-# 2259| Type = [VoidType] void
-# 2259| ValueCategory = prvalue
-# 2259| getChild(0): [FunctionCall] call to get
-# 2259| Type = [LValueReferenceType] int &
-# 2259| ValueCategory = prvalue
-# 2259| getArgument(0): [VariableAccess] t
-# 2259| Type = [LValueReferenceType] int &
-# 2259| ValueCategory = prvalue(load)
-# 2259| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2259| Type = [LValueReferenceType] int &
-# 2259| ValueCategory = prvalue
-# 2259| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
-# 2259| Type = [IntType] int
-# 2259| ValueCategory = lvalue
-# 2259| getChild(0).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2259| Type = [IntType] int
-# 2259| ValueCategory = lvalue
-# 2260| getStmt(1): [ReturnStmt] return ...
-# 2262| [TopLevelFunction] void vacuous_destructor_call::non_vacuous_destructor_call()
-# 2262| :
-# 2262| getEntryPoint(): [BlockStmt] { ... }
-# 2263| getStmt(0): [DeclStmt] declaration
-# 2263| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
-# 2263| Type = [Class] ClassWithDestructor
-# 2263| getVariable().getInitializer(): [Initializer] initializer for c
-# 2263| getExpr(): [ConstructorCall] call to ClassWithDestructor
-# 2263| Type = [VoidType] void
-# 2263| ValueCategory = prvalue
-# 2264| getStmt(1): [ExprStmt] ExprStmt
-# 2264| getExpr(): [FunctionCall] call to call_destructor
-# 2264| Type = [VoidType] void
-# 2264| ValueCategory = prvalue
-# 2264| getArgument(0): [VariableAccess] c
-# 2264| Type = [Class] ClassWithDestructor
-# 2264| ValueCategory = lvalue
-# 2264| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2264| Type = [LValueReferenceType] ClassWithDestructor &
-# 2264| ValueCategory = prvalue
-# 2265| getStmt(2): [ReturnStmt] return ...
-# 2265| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2250| getStmt(3): [ReturnStmt] return ...
+# 2250| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2250| Type = [VoidType] void
+# 2250| ValueCategory = prvalue
+# 2250| getQualifier(): [VariableAccess] b
+# 2250| Type = [Class] ClassWithDestructor
+# 2250| ValueCategory = lvalue
+# 2250| getImplicitDestructorCall(1): [DestructorCall] call to ~ClassWithDestructor
+# 2250| Type = [VoidType] void
+# 2250| ValueCategory = prvalue
+# 2250| getQualifier(): [VariableAccess] a
+# 2250| Type = [Class] ClassWithDestructor
+# 2250| ValueCategory = lvalue
+# 2252| [GlobalVariable] ClassWithDestructor global_class_with_destructor
+# 2252| getInitializer(): [Initializer] initializer for global_class_with_destructor
+# 2252| getExpr(): [ConstructorCall] call to ClassWithDestructor
+# 2252| Type = [VoidType] void
+# 2252| ValueCategory = prvalue
+# 2256| [FunctionTemplateInstantiation,TopLevelFunction] ClassWithDestructor& vacuous_destructor_call::get(ClassWithDestructor&)
+# 2256| :
+# 2256| getParameter(0): [Parameter] t
+# 2256| Type = [LValueReferenceType] ClassWithDestructor &
+# 2256| getEntryPoint(): [BlockStmt] { ... }
+# 2256| getStmt(0): [ReturnStmt] return ...
+# 2256| getExpr(): [VariableAccess] t
+# 2256| Type = [LValueReferenceType] ClassWithDestructor &
+# 2256| ValueCategory = prvalue(load)
+# 2256| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2256| Type = [LValueReferenceType] ClassWithDestructor &
+# 2256| ValueCategory = prvalue
+# 2256| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
+# 2256| Type = [Class] ClassWithDestructor
+# 2256| ValueCategory = lvalue
+# 2256| [TemplateFunction,TopLevelFunction] T& vacuous_destructor_call::get(T&)
+# 2256| :
+# 2256| getParameter(0): [Parameter] t
+# 2256| Type = [LValueReferenceType] T &
+# 2256| getEntryPoint(): [BlockStmt] { ... }
+# 2256| getStmt(0): [ReturnStmt] return ...
+# 2256| getExpr(): [VariableAccess] t
+# 2256| Type = [LValueReferenceType] T &
+# 2256| ValueCategory = prvalue(load)
+# 2256| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2256| Type = [TemplateParameter] T
+# 2256| ValueCategory = lvalue
+# 2256| [FunctionTemplateInstantiation,TopLevelFunction] int& vacuous_destructor_call::get(int&)
+# 2256| :
+# 2256| getParameter(0): [Parameter] t
+# 2256| Type = [LValueReferenceType] int &
+# 2256| getEntryPoint(): [BlockStmt] { ... }
+# 2256| getStmt(0): [ReturnStmt] return ...
+# 2256| getExpr(): [VariableAccess] t
+# 2256| Type = [LValueReferenceType] int &
+# 2256| ValueCategory = prvalue(load)
+# 2256| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2256| Type = [LValueReferenceType] int &
+# 2256| ValueCategory = prvalue
+# 2256| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
+# 2256| Type = [IntType] int
+# 2256| ValueCategory = lvalue
+# 2259| [FunctionTemplateInstantiation,TopLevelFunction] void vacuous_destructor_call::call_destructor(ClassWithDestructor&)
+# 2259| :
+# 2259| getParameter(0): [Parameter] t
+# 2259| Type = [LValueReferenceType] ClassWithDestructor &
+# 2259| getEntryPoint(): [BlockStmt] { ... }
+# 2260| getStmt(0): [ExprStmt] ExprStmt
+# 2260| getExpr(): [DestructorCall] call to ~ClassWithDestructor
+# 2260| Type = [VoidType] void
+# 2260| ValueCategory = prvalue
+# 2260| getQualifier(): [FunctionCall] call to get
+# 2260| Type = [LValueReferenceType] ClassWithDestructor &
+# 2260| ValueCategory = prvalue
+# 2260| getArgument(0): [VariableAccess] t
+# 2260| Type = [LValueReferenceType] ClassWithDestructor &
+# 2260| ValueCategory = prvalue(load)
+# 2260| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2260| Type = [LValueReferenceType] ClassWithDestructor &
+# 2260| ValueCategory = prvalue
+# 2260| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
+# 2260| Type = [Class] ClassWithDestructor
+# 2260| ValueCategory = lvalue
+# 2260| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2260| Type = [Class] ClassWithDestructor
+# 2260| ValueCategory = lvalue
+# 2261| getStmt(1): [ReturnStmt] return ...
+# 2259| [TemplateFunction,TopLevelFunction] void vacuous_destructor_call::call_destructor(T&)
+# 2259| :
+# 2259| getParameter(0): [Parameter] t
+# 2259| Type = [LValueReferenceType] T &
+# 2259| getEntryPoint(): [BlockStmt] { ... }
+# 2260| getStmt(0): [ExprStmt] ExprStmt
+# 2260| getExpr(): [ExprCall] call to expression
+# 2260| Type = [UnknownType] unknown
+# 2260| ValueCategory = prvalue
+# 2260| getExpr(): [Literal] Unknown literal
+# 2260| Type = [UnknownType] unknown
+# 2260| ValueCategory = prvalue
+# 2260| getChild(-1): [ExprCall] call to expression
+# 2260| Type = [UnknownType] unknown
+# 2260| ValueCategory = prvalue
+# 2260| getExpr(): [Literal] Unknown literal
+# 2260| Type = [UnknownType] unknown
+# 2260| ValueCategory = prvalue
+# 2260| getArgument(0): [VariableAccess] t
+# 2260| Type = [LValueReferenceType] T &
+# 2260| ValueCategory = prvalue(load)
+# 2260| getArgument(0).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2260| Type = [TemplateParameter] T
+# 2260| ValueCategory = lvalue
+# 2261| getStmt(1): [ReturnStmt] return ...
+# 2259| [FunctionTemplateInstantiation,TopLevelFunction] void vacuous_destructor_call::call_destructor(int&)
+# 2259| :
+# 2259| getParameter(0): [Parameter] t
+# 2259| Type = [LValueReferenceType] int &
+# 2259| getEntryPoint(): [BlockStmt] { ... }
+# 2260| getStmt(0): [ExprStmt] ExprStmt
+# 2260| getExpr(): [VacuousDestructorCall] (vacuous destructor call)
+# 2260| Type = [VoidType] void
+# 2260| ValueCategory = prvalue
+# 2260| getChild(0): [FunctionCall] call to get
+# 2260| Type = [LValueReferenceType] int &
+# 2260| ValueCategory = prvalue
+# 2260| getArgument(0): [VariableAccess] t
+# 2260| Type = [LValueReferenceType] int &
+# 2260| ValueCategory = prvalue(load)
+# 2260| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2260| Type = [LValueReferenceType] int &
+# 2260| ValueCategory = prvalue
+# 2260| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
+# 2260| Type = [IntType] int
+# 2260| ValueCategory = lvalue
+# 2260| getChild(0).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2260| Type = [IntType] int
+# 2260| ValueCategory = lvalue
+# 2261| getStmt(1): [ReturnStmt] return ...
+# 2263| [TopLevelFunction] void vacuous_destructor_call::non_vacuous_destructor_call()
+# 2263| :
+# 2263| getEntryPoint(): [BlockStmt] { ... }
+# 2264| getStmt(0): [DeclStmt] declaration
+# 2264| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
+# 2264| Type = [Class] ClassWithDestructor
+# 2264| getVariable().getInitializer(): [Initializer] initializer for c
+# 2264| getExpr(): [ConstructorCall] call to ClassWithDestructor
+# 2264| Type = [VoidType] void
+# 2264| ValueCategory = prvalue
+# 2265| getStmt(1): [ExprStmt] ExprStmt
+# 2265| getExpr(): [FunctionCall] call to call_destructor
# 2265| Type = [VoidType] void
# 2265| ValueCategory = prvalue
-# 2265| getQualifier(): [VariableAccess] c
+# 2265| getArgument(0): [VariableAccess] c
# 2265| Type = [Class] ClassWithDestructor
# 2265| ValueCategory = lvalue
-# 2267| [TopLevelFunction] void vacuous_destructor_call::vacuous_destructor_call()
-# 2267| :
-# 2267| getEntryPoint(): [BlockStmt] { ... }
-# 2268| getStmt(0): [DeclStmt] declaration
-# 2268| getDeclarationEntry(0): [VariableDeclarationEntry] definition of i
-# 2268| Type = [IntType] int
-# 2269| getStmt(1): [ExprStmt] ExprStmt
-# 2269| getExpr(): [FunctionCall] call to call_destructor
-# 2269| Type = [VoidType] void
-# 2269| ValueCategory = prvalue
-# 2269| getArgument(0): [VariableAccess] i
-# 2269| Type = [IntType] int
-# 2269| ValueCategory = lvalue
-# 2269| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2269| Type = [LValueReferenceType] int &
-# 2269| ValueCategory = prvalue
-# 2270| getStmt(2): [ReturnStmt] return ...
-# 2273| [TopLevelFunction] void TryCatchDestructors(bool)
-# 2273| :
-# 2273| getParameter(0): [Parameter] b
-# 2273| Type = [BoolType] bool
-# 2273| getEntryPoint(): [BlockStmt] { ... }
-# 2274| getStmt(0): [TryStmt] try { ... }
-# 2274| getStmt(): [BlockStmt] { ... }
-# 2275| getStmt(0): [DeclStmt] declaration
-# 2275| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
-# 2275| Type = [Struct] String
-# 2275| getVariable().getInitializer(): [Initializer] initializer for s
-# 2275| getExpr(): [ConstructorCall] call to String
-# 2275| Type = [VoidType] void
-# 2275| ValueCategory = prvalue
-# 2276| getStmt(1): [IfStmt] if (...) ...
-# 2276| getCondition(): [VariableAccess] b
-# 2276| Type = [BoolType] bool
-# 2276| ValueCategory = prvalue(load)
-# 2276| getThen(): [BlockStmt] { ... }
-# 2277| getStmt(0): [ExprStmt] ExprStmt
-# 2277| getExpr(): [ThrowExpr] throw ...
-# 2277| Type = [PointerType] const char *
-# 2277| ValueCategory = prvalue
-# 2277| getExpr(): string literal
-# 2277| Type = [ArrayType] const char[15]
-# 2277| Value = [StringLiteral] "string literal"
-# 2277| ValueCategory = lvalue
-# 2280| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2280| Type = [VoidType] void
-# 2280| ValueCategory = prvalue
-# 2280| getQualifier(): [VariableAccess] s
-# 2280| Type = [Struct] String
-# 2280| ValueCategory = lvalue
-# 2277| getExpr().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
-# 2277| Type = [PointerType] const char *
-# 2277| ValueCategory = prvalue
-# 2279| getStmt(2): [DeclStmt] declaration
-# 2279| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s2
-# 2279| Type = [Struct] String
-# 2279| getVariable().getInitializer(): [Initializer] initializer for s2
-# 2279| getExpr(): [ConstructorCall] call to String
-# 2279| Type = [VoidType] void
-# 2279| ValueCategory = prvalue
-# 2280| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2280| Type = [VoidType] void
-# 2280| ValueCategory = prvalue
-# 2280| getQualifier(): [VariableAccess] s2
+# 2265| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2265| Type = [LValueReferenceType] ClassWithDestructor &
+# 2265| ValueCategory = prvalue
+# 2266| getStmt(2): [ReturnStmt] return ...
+# 2266| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2266| Type = [VoidType] void
+# 2266| ValueCategory = prvalue
+# 2266| getQualifier(): [VariableAccess] c
+# 2266| Type = [Class] ClassWithDestructor
+# 2266| ValueCategory = lvalue
+# 2268| [TopLevelFunction] void vacuous_destructor_call::vacuous_destructor_call()
+# 2268| :
+# 2268| getEntryPoint(): [BlockStmt] { ... }
+# 2269| getStmt(0): [DeclStmt] declaration
+# 2269| getDeclarationEntry(0): [VariableDeclarationEntry] definition of i
+# 2269| Type = [IntType] int
+# 2270| getStmt(1): [ExprStmt] ExprStmt
+# 2270| getExpr(): [FunctionCall] call to call_destructor
+# 2270| Type = [VoidType] void
+# 2270| ValueCategory = prvalue
+# 2270| getArgument(0): [VariableAccess] i
+# 2270| Type = [IntType] int
+# 2270| ValueCategory = lvalue
+# 2270| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2270| Type = [LValueReferenceType] int &
+# 2270| ValueCategory = prvalue
+# 2271| getStmt(2): [ReturnStmt] return ...
+# 2274| [TopLevelFunction] void TryCatchDestructors(bool)
+# 2274| :
+# 2274| getParameter(0): [Parameter] b
+# 2274| Type = [BoolType] bool
+# 2274| getEntryPoint(): [BlockStmt] { ... }
+# 2275| getStmt(0): [TryStmt] try { ... }
+# 2275| getStmt(): [BlockStmt] { ... }
+# 2276| getStmt(0): [DeclStmt] declaration
+# 2276| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
+# 2276| Type = [Struct] String
+# 2276| getVariable().getInitializer(): [Initializer] initializer for s
+# 2276| getExpr(): [ConstructorCall] call to String
+# 2276| Type = [VoidType] void
+# 2276| ValueCategory = prvalue
+# 2277| getStmt(1): [IfStmt] if (...) ...
+# 2277| getCondition(): [VariableAccess] b
+# 2277| Type = [BoolType] bool
+# 2277| ValueCategory = prvalue(load)
+# 2277| getThen(): [BlockStmt] { ... }
+# 2278| getStmt(0): [ExprStmt] ExprStmt
+# 2278| getExpr(): [ThrowExpr] throw ...
+# 2278| Type = [PointerType] const char *
+# 2278| ValueCategory = prvalue
+# 2278| getExpr(): string literal
+# 2278| Type = [ArrayType] const char[15]
+# 2278| Value = [StringLiteral] "string literal"
+# 2278| ValueCategory = lvalue
+# 2281| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2281| Type = [VoidType] void
+# 2281| ValueCategory = prvalue
+# 2281| getQualifier(): [VariableAccess] s
+# 2281| Type = [Struct] String
+# 2281| ValueCategory = lvalue
+# 2278| getExpr().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
+# 2278| Type = [PointerType] const char *
+# 2278| ValueCategory = prvalue
+# 2280| getStmt(2): [DeclStmt] declaration
+# 2280| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s2
# 2280| Type = [Struct] String
-# 2280| ValueCategory = lvalue
-# 2280| getImplicitDestructorCall(1): [DestructorCall] call to ~String
-# 2280| Type = [VoidType] void
-# 2280| ValueCategory = prvalue
-# 2280| getQualifier(): [VariableAccess] s
-# 2280| Type = [Struct] String
-# 2280| ValueCategory = lvalue
-# 2281| getChild(1): [Handler]
-# 2281| getBlock(): [CatchBlock] { ... }
-# 2282| getStmt(0): [ExprStmt] ExprStmt
-# 2282| getExpr(): [ThrowExpr] throw ...
-# 2282| Type = [Struct] String
-# 2282| ValueCategory = prvalue
-# 2282| getExpr(): [ConstructorCall] call to String
-# 2282| Type = [VoidType] void
-# 2282| ValueCategory = prvalue
-# 2282| getArgument(0): [VariableAccess] s
-# 2282| Type = [PointerType] const char *
-# 2282| ValueCategory = prvalue(load)
-# 2284| getChild(2): [Handler]
-# 2284| getBlock(): [CatchBlock] { ... }
-# 2286| getChild(3): [Handler]
-# 2286| getBlock(): [CatchAnyBlock] { ... }
-# 2287| getStmt(0): [ExprStmt] ExprStmt
-# 2287| getExpr(): [ReThrowExpr] re-throw exception
-# 2287| Type = [VoidType] void
-# 2287| ValueCategory = prvalue
-# 2289| getStmt(1): [ReturnStmt] return ...
-# 2291| [TopLevelFunction] void IfDestructors(bool)
-# 2291| :
-# 2291| getParameter(0): [Parameter] b
-# 2291| Type = [BoolType] bool
-# 2291| getEntryPoint(): [BlockStmt] { ... }
-# 2292| getStmt(0): [DeclStmt] declaration
-# 2292| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s1
-# 2292| Type = [Struct] String
-# 2292| getVariable().getInitializer(): [Initializer] initializer for s1
-# 2292| getExpr(): [ConstructorCall] call to String
-# 2292| Type = [VoidType] void
-# 2292| ValueCategory = prvalue
-# 2293| getStmt(1): [IfStmt] if (...) ...
-# 2293| getCondition(): [VariableAccess] b
-# 2293| Type = [BoolType] bool
-# 2293| ValueCategory = prvalue(load)
-# 2293| getThen(): [BlockStmt] { ... }
-# 2294| getStmt(0): [DeclStmt] declaration
-# 2294| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s2
-# 2294| Type = [Struct] String
-# 2294| getVariable().getInitializer(): [Initializer] initializer for s2
-# 2294| getExpr(): [ConstructorCall] call to String
-# 2294| Type = [VoidType] void
-# 2294| ValueCategory = prvalue
-# 2295| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2295| Type = [VoidType] void
-# 2295| ValueCategory = prvalue
-# 2295| getQualifier(): [VariableAccess] s2
+# 2280| getVariable().getInitializer(): [Initializer] initializer for s2
+# 2280| getExpr(): [ConstructorCall] call to String
+# 2280| Type = [VoidType] void
+# 2280| ValueCategory = prvalue
+# 2281| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2281| Type = [VoidType] void
+# 2281| ValueCategory = prvalue
+# 2281| getQualifier(): [VariableAccess] s2
+# 2281| Type = [Struct] String
+# 2281| ValueCategory = lvalue
+# 2281| getImplicitDestructorCall(1): [DestructorCall] call to ~String
+# 2281| Type = [VoidType] void
+# 2281| ValueCategory = prvalue
+# 2281| getQualifier(): [VariableAccess] s
+# 2281| Type = [Struct] String
+# 2281| ValueCategory = lvalue
+# 2282| getChild(1): [Handler]
+# 2282| getBlock(): [CatchBlock] { ... }
+# 2283| getStmt(0): [ExprStmt] ExprStmt
+# 2283| getExpr(): [ThrowExpr] throw ...
+# 2283| Type = [Struct] String
+# 2283| ValueCategory = prvalue
+# 2283| getExpr(): [ConstructorCall] call to String
+# 2283| Type = [VoidType] void
+# 2283| ValueCategory = prvalue
+# 2283| getArgument(0): [VariableAccess] s
+# 2283| Type = [PointerType] const char *
+# 2283| ValueCategory = prvalue(load)
+# 2285| getChild(2): [Handler]
+# 2285| getBlock(): [CatchBlock] { ... }
+# 2287| getChild(3): [Handler]
+# 2287| getBlock(): [CatchAnyBlock] { ... }
+# 2288| getStmt(0): [ExprStmt] ExprStmt
+# 2288| getExpr(): [ReThrowExpr] re-throw exception
+# 2288| Type = [VoidType] void
+# 2288| ValueCategory = prvalue
+# 2290| getStmt(1): [ReturnStmt] return ...
+# 2292| [TopLevelFunction] void IfDestructors(bool)
+# 2292| :
+# 2292| getParameter(0): [Parameter] b
+# 2292| Type = [BoolType] bool
+# 2292| getEntryPoint(): [BlockStmt] { ... }
+# 2293| getStmt(0): [DeclStmt] declaration
+# 2293| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s1
+# 2293| Type = [Struct] String
+# 2293| getVariable().getInitializer(): [Initializer] initializer for s1
+# 2293| getExpr(): [ConstructorCall] call to String
+# 2293| Type = [VoidType] void
+# 2293| ValueCategory = prvalue
+# 2294| getStmt(1): [IfStmt] if (...) ...
+# 2294| getCondition(): [VariableAccess] b
+# 2294| Type = [BoolType] bool
+# 2294| ValueCategory = prvalue(load)
+# 2294| getThen(): [BlockStmt] { ... }
+# 2295| getStmt(0): [DeclStmt] declaration
+# 2295| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s2
# 2295| Type = [Struct] String
-# 2295| ValueCategory = lvalue
-# 2295| getElse(): [BlockStmt] { ... }
-# 2296| getStmt(0): [DeclStmt] declaration
-# 2296| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s3
+# 2295| getVariable().getInitializer(): [Initializer] initializer for s2
+# 2295| getExpr(): [ConstructorCall] call to String
+# 2295| Type = [VoidType] void
+# 2295| ValueCategory = prvalue
+# 2296| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2296| Type = [VoidType] void
+# 2296| ValueCategory = prvalue
+# 2296| getQualifier(): [VariableAccess] s2
# 2296| Type = [Struct] String
-# 2296| getVariable().getInitializer(): [Initializer] initializer for s3
-# 2296| getExpr(): [ConstructorCall] call to String
-# 2296| Type = [VoidType] void
-# 2296| ValueCategory = prvalue
-# 2297| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2297| Type = [VoidType] void
-# 2297| ValueCategory = prvalue
-# 2297| getQualifier(): [VariableAccess] s3
+# 2296| ValueCategory = lvalue
+# 2296| getElse(): [BlockStmt] { ... }
+# 2297| getStmt(0): [DeclStmt] declaration
+# 2297| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s3
# 2297| Type = [Struct] String
-# 2297| ValueCategory = lvalue
-# 2298| getStmt(2): [DeclStmt] declaration
-# 2298| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s4
-# 2298| Type = [Struct] String
-# 2298| getVariable().getInitializer(): [Initializer] initializer for s4
-# 2298| getExpr(): [ConstructorCall] call to String
-# 2298| Type = [VoidType] void
-# 2298| ValueCategory = prvalue
-# 2299| getStmt(3): [ReturnStmt] return ...
-# 2299| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2299| Type = [VoidType] void
-# 2299| ValueCategory = prvalue
-# 2299| getQualifier(): [VariableAccess] s4
-# 2299| Type = [Struct] String
-# 2299| ValueCategory = lvalue
-# 2299| getImplicitDestructorCall(1): [DestructorCall] call to ~String
-# 2299| Type = [VoidType] void
-# 2299| ValueCategory = prvalue
-# 2299| getQualifier(): [VariableAccess] s1
-# 2299| Type = [Struct] String
-# 2299| ValueCategory = lvalue
-# 2301| [TopLevelFunction] void ForDestructors()
-# 2301| :
-# 2301| getEntryPoint(): [BlockStmt] { ... }
-# 2302| getStmt(0): [DeclStmt] declaration
-# 2302| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
-# 2302| Type = [PlainCharType] char
-# 2302| getVariable().getInitializer(): [Initializer] initializer for c
-# 2302| getExpr(): [CharLiteral] 97
-# 2302| Type = [PlainCharType] char
-# 2302| Value = [CharLiteral] 97
-# 2302| ValueCategory = prvalue
-# 2303| getStmt(1): [ForStmt] for(...;...;...) ...
-# 2303| getInitialization(): [DeclStmt] declaration
-# 2303| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
-# 2303| Type = [Struct] String
-# 2303| getVariable().getInitializer(): [Initializer] initializer for s
-# 2303| getExpr(): [ConstructorCall] call to String
-# 2303| Type = [VoidType] void
-# 2303| ValueCategory = prvalue
-# 2303| getArgument(0): hello
-# 2303| Type = [ArrayType] const char[6]
-# 2303| Value = [StringLiteral] "hello"
-# 2303| ValueCategory = lvalue
-# 2303| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
-# 2303| Type = [PointerType] const char *
-# 2303| ValueCategory = prvalue
-# 2303| getCondition(): [NEExpr] ... != ...
-# 2303| Type = [BoolType] bool
-# 2303| ValueCategory = prvalue
-# 2303| getLeftOperand(): [VariableAccess] c
-# 2303| Type = [PlainCharType] char
-# 2303| ValueCategory = prvalue(load)
-# 2303| getRightOperand(): [Literal] 0
-# 2303| Type = [IntType] int
-# 2303| Value = [Literal] 0
-# 2303| ValueCategory = prvalue
-# 2303| getLeftOperand().getFullyConverted(): [CStyleCast] (int)...
-# 2303| Conversion = [IntegralConversion] integral conversion
-# 2303| Type = [IntType] int
-# 2303| ValueCategory = prvalue
-# 2303| getUpdate(): [AssignExpr] ... = ...
+# 2297| getVariable().getInitializer(): [Initializer] initializer for s3
+# 2297| getExpr(): [ConstructorCall] call to String
+# 2297| Type = [VoidType] void
+# 2297| ValueCategory = prvalue
+# 2298| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2298| Type = [VoidType] void
+# 2298| ValueCategory = prvalue
+# 2298| getQualifier(): [VariableAccess] s3
+# 2298| Type = [Struct] String
+# 2298| ValueCategory = lvalue
+# 2299| getStmt(2): [DeclStmt] declaration
+# 2299| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s4
+# 2299| Type = [Struct] String
+# 2299| getVariable().getInitializer(): [Initializer] initializer for s4
+# 2299| getExpr(): [ConstructorCall] call to String
+# 2299| Type = [VoidType] void
+# 2299| ValueCategory = prvalue
+# 2300| getStmt(3): [ReturnStmt] return ...
+# 2300| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2300| Type = [VoidType] void
+# 2300| ValueCategory = prvalue
+# 2300| getQualifier(): [VariableAccess] s4
+# 2300| Type = [Struct] String
+# 2300| ValueCategory = lvalue
+# 2300| getImplicitDestructorCall(1): [DestructorCall] call to ~String
+# 2300| Type = [VoidType] void
+# 2300| ValueCategory = prvalue
+# 2300| getQualifier(): [VariableAccess] s1
+# 2300| Type = [Struct] String
+# 2300| ValueCategory = lvalue
+# 2302| [TopLevelFunction] void ForDestructors()
+# 2302| :
+# 2302| getEntryPoint(): [BlockStmt] { ... }
+# 2303| getStmt(0): [DeclStmt] declaration
+# 2303| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
# 2303| Type = [PlainCharType] char
-# 2303| ValueCategory = lvalue
-# 2303| getLValue(): [VariableAccess] c
-# 2303| Type = [PlainCharType] char
-# 2303| ValueCategory = lvalue
-# 2303| getRValue(): [FunctionCall] call to pop_back
-# 2303| Type = [PlainCharType] char
-# 2303| ValueCategory = prvalue
-# 2303| getQualifier(): [VariableAccess] s
-# 2303| Type = [Struct] String
-# 2303| ValueCategory = lvalue
-# 2303| getStmt(): [BlockStmt] { ... }
-# 2304| getStmt(0): [DeclStmt] declaration
-# 2304| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s2
-# 2304| Type = [Struct] String
-# 2304| getVariable().getInitializer(): [Initializer] initializer for s2
-# 2304| getExpr(): [ConstructorCall] call to String
-# 2304| Type = [VoidType] void
+# 2303| getVariable().getInitializer(): [Initializer] initializer for c
+# 2303| getExpr(): [CharLiteral] 97
+# 2303| Type = [PlainCharType] char
+# 2303| Value = [CharLiteral] 97
+# 2303| ValueCategory = prvalue
+# 2304| getStmt(1): [ForStmt] for(...;...;...) ...
+# 2304| getInitialization(): [DeclStmt] declaration
+# 2304| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
+# 2304| Type = [Struct] String
+# 2304| getVariable().getInitializer(): [Initializer] initializer for s
+# 2304| getExpr(): [ConstructorCall] call to String
+# 2304| Type = [VoidType] void
+# 2304| ValueCategory = prvalue
+# 2304| getArgument(0): hello
+# 2304| Type = [ArrayType] const char[6]
+# 2304| Value = [StringLiteral] "hello"
+# 2304| ValueCategory = lvalue
+# 2304| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
+# 2304| Type = [PointerType] const char *
# 2304| ValueCategory = prvalue
-# 2305| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2305| Type = [VoidType] void
-# 2305| ValueCategory = prvalue
-# 2305| getQualifier(): [VariableAccess] s2
+# 2304| getCondition(): [NEExpr] ... != ...
+# 2304| Type = [BoolType] bool
+# 2304| ValueCategory = prvalue
+# 2304| getLeftOperand(): [VariableAccess] c
+# 2304| Type = [PlainCharType] char
+# 2304| ValueCategory = prvalue(load)
+# 2304| getRightOperand(): [Literal] 0
+# 2304| Type = [IntType] int
+# 2304| Value = [Literal] 0
+# 2304| ValueCategory = prvalue
+# 2304| getLeftOperand().getFullyConverted(): [CStyleCast] (int)...
+# 2304| Conversion = [IntegralConversion] integral conversion
+# 2304| Type = [IntType] int
+# 2304| ValueCategory = prvalue
+# 2304| getUpdate(): [AssignExpr] ... = ...
+# 2304| Type = [PlainCharType] char
+# 2304| ValueCategory = lvalue
+# 2304| getLValue(): [VariableAccess] c
+# 2304| Type = [PlainCharType] char
+# 2304| ValueCategory = lvalue
+# 2304| getRValue(): [FunctionCall] call to pop_back
+# 2304| Type = [PlainCharType] char
+# 2304| ValueCategory = prvalue
+# 2304| getQualifier(): [VariableAccess] s
+# 2304| Type = [Struct] String
+# 2304| ValueCategory = lvalue
+# 2304| getStmt(): [BlockStmt] { ... }
+# 2305| getStmt(0): [DeclStmt] declaration
+# 2305| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s2
# 2305| Type = [Struct] String
-# 2305| ValueCategory = lvalue
-# 2303| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2303| Type = [VoidType] void
-# 2303| ValueCategory = prvalue
-# 2303| getQualifier(): [VariableAccess] s
-# 2303| Type = [Struct] String
-# 2303| ValueCategory = lvalue
-# 2307| getStmt(2): [RangeBasedForStmt] for(...:...) ...
-# 2307| getChild(1): [DeclStmt] declaration
-# 2307| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
-# 2307| Type = [RValueReferenceType] vector &&
+# 2305| getVariable().getInitializer(): [Initializer] initializer for s2
+# 2305| getExpr(): [ConstructorCall] call to String
+# 2305| Type = [VoidType] void
+# 2305| ValueCategory = prvalue
+# 2306| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2306| Type = [VoidType] void
+# 2306| ValueCategory = prvalue
+# 2306| getQualifier(): [VariableAccess] s2
+# 2306| Type = [Struct] String
+# 2306| ValueCategory = lvalue
+# 2304| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2304| Type = [VoidType] void
+# 2304| ValueCategory = prvalue
+# 2304| getQualifier(): [VariableAccess] s
+# 2304| Type = [Struct] String
+# 2304| ValueCategory = lvalue
+# 2308| getStmt(2): [RangeBasedForStmt] for(...:...) ...
+# 2308| getChild(1): [DeclStmt] declaration
+# 2308| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
+# 2308| Type = [RValueReferenceType] vector &&
#-----| getVariable().getInitializer(): [Initializer] initializer for (__range)
-# 2307| getExpr(): [ConstructorCall] call to vector
-# 2307| Type = [VoidType] void
-# 2307| ValueCategory = prvalue
-# 2307| getArgument(0): [ConstructorCall] call to String
-# 2307| Type = [VoidType] void
-# 2307| ValueCategory = prvalue
-# 2307| getArgument(0): hello
-# 2307| Type = [ArrayType] const char[6]
-# 2307| Value = [StringLiteral] "hello"
-# 2307| ValueCategory = lvalue
-# 2307| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
-# 2307| Type = [PointerType] const char *
-# 2307| ValueCategory = prvalue
-# 2307| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
-# 2307| Type = [Struct] String
-# 2307| ValueCategory = lvalue
-# 2307| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2307| Type = [LValueReferenceType] vector &
-# 2307| ValueCategory = prvalue
-# 2307| getExpr(): [TemporaryObjectExpr] temporary object
-# 2307| Type = [ClassTemplateInstantiation,Struct] vector
-# 2307| ValueCategory = xvalue
-# 2307| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2307| Type = [VoidType] void
-# 2307| ValueCategory = prvalue
-# 2307| getQualifier(): [ReuseExpr] reuse of temporary object
-# 2307| Type = [Struct] String
-# 2307| ValueCategory = xvalue
-# 2307| getBeginEndDeclaration(): [DeclStmt] declaration
-# 2307| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
-# 2307| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2308| getExpr(): [ConstructorCall] call to vector
+# 2308| Type = [VoidType] void
+# 2308| ValueCategory = prvalue
+# 2308| getArgument(0): [ConstructorCall] call to String
+# 2308| Type = [VoidType] void
+# 2308| ValueCategory = prvalue
+# 2308| getArgument(0): hello
+# 2308| Type = [ArrayType] const char[6]
+# 2308| Value = [StringLiteral] "hello"
+# 2308| ValueCategory = lvalue
+# 2308| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
+# 2308| Type = [PointerType] const char *
+# 2308| ValueCategory = prvalue
+# 2308| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2308| Type = [Struct] String
+# 2308| ValueCategory = lvalue
+# 2308| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2308| Type = [LValueReferenceType] vector &
+# 2308| ValueCategory = prvalue
+# 2308| getExpr(): [TemporaryObjectExpr] temporary object
+# 2308| Type = [ClassTemplateInstantiation,Struct] vector
+# 2308| ValueCategory = xvalue
+# 2308| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2308| Type = [VoidType] void
+# 2308| ValueCategory = prvalue
+# 2308| getQualifier(): [ReuseExpr] reuse of temporary object
+# 2308| Type = [Struct] String
+# 2308| ValueCategory = xvalue
+# 2308| getBeginEndDeclaration(): [DeclStmt] declaration
+# 2308| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
+# 2308| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
#-----| getVariable().getInitializer(): [Initializer] initializer for (__begin)
-# 2307| getExpr(): [FunctionCall] call to begin
-# 2307| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2307| ValueCategory = prvalue
-# 2307| getQualifier(): [VariableAccess] (__range)
-# 2307| Type = [RValueReferenceType] vector &&
-# 2307| ValueCategory = prvalue(load)
+# 2308| getExpr(): [FunctionCall] call to begin
+# 2308| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2308| ValueCategory = prvalue
+# 2308| getQualifier(): [VariableAccess] (__range)
+# 2308| Type = [RValueReferenceType] vector &&
+# 2308| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const vector)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const vector
@@ -20573,15 +20591,15 @@ ir.cpp:
#-----| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
#-----| Type = [ClassTemplateInstantiation,Struct] vector
#-----| ValueCategory = lvalue
-# 2307| getDeclarationEntry(1): [VariableDeclarationEntry] declaration of (__end)
-# 2307| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2308| getDeclarationEntry(1): [VariableDeclarationEntry] declaration of (__end)
+# 2308| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
#-----| getVariable().getInitializer(): [Initializer] initializer for (__end)
-# 2307| getExpr(): [FunctionCall] call to end
-# 2307| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2307| ValueCategory = prvalue
-# 2307| getQualifier(): [VariableAccess] (__range)
-# 2307| Type = [RValueReferenceType] vector &&
-# 2307| ValueCategory = prvalue(load)
+# 2308| getExpr(): [FunctionCall] call to end
+# 2308| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2308| ValueCategory = prvalue
+# 2308| getQualifier(): [VariableAccess] (__range)
+# 2308| Type = [RValueReferenceType] vector &&
+# 2308| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const vector)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const vector
@@ -20589,18 +20607,18 @@ ir.cpp:
#-----| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
#-----| Type = [ClassTemplateInstantiation,Struct] vector
#-----| ValueCategory = lvalue
-# 2307| getCondition(): [FunctionCall] call to operator!=
-# 2307| Type = [BoolType] bool
-# 2307| ValueCategory = prvalue
-# 2307| getQualifier(): [VariableAccess] (__begin)
-# 2307| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2307| ValueCategory = lvalue
-# 2307| getArgument(0): [ConstructorCall] call to iterator
-# 2307| Type = [VoidType] void
-# 2307| ValueCategory = prvalue
-# 2307| getArgument(0): [VariableAccess] (__end)
-# 2307| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2307| ValueCategory = lvalue
+# 2308| getCondition(): [FunctionCall] call to operator!=
+# 2308| Type = [BoolType] bool
+# 2308| ValueCategory = prvalue
+# 2308| getQualifier(): [VariableAccess] (__begin)
+# 2308| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2308| ValueCategory = lvalue
+# 2308| getArgument(0): [ConstructorCall] call to iterator
+# 2308| Type = [VoidType] void
+# 2308| ValueCategory = prvalue
+# 2308| getArgument(0): [VariableAccess] (__end)
+# 2308| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2308| ValueCategory = lvalue
#-----| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
#-----| Type = [LValueReferenceType] const iterator &
#-----| ValueCategory = prvalue
@@ -20615,1491 +20633,1497 @@ ir.cpp:
#-----| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
#-----| Type = [ClassTemplateInstantiation,Struct] iterator
#-----| ValueCategory = lvalue
-# 2307| getUpdate(): [FunctionCall] call to operator++
-# 2307| Type = [LValueReferenceType] iterator &
-# 2307| ValueCategory = prvalue
-# 2307| getQualifier(): [VariableAccess] (__begin)
-# 2307| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2307| ValueCategory = lvalue
-# 2307| getChild(5): [DeclStmt] declaration
-# 2307| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
-# 2307| Type = [Struct] String
-# 2307| getVariable().getInitializer(): [Initializer] initializer for s
-# 2307| getExpr(): [ConstructorCall] call to String
-# 2307| Type = [VoidType] void
-# 2307| ValueCategory = prvalue
-# 2307| getArgument(0): [OverloadedPointerDereferenceExpr] call to operator*
-# 2307| Type = [LValueReferenceType] String &
-# 2307| ValueCategory = prvalue
-# 2307| getQualifier(): [VariableAccess] (__begin)
-# 2307| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2307| ValueCategory = lvalue
+# 2308| getUpdate(): [FunctionCall] call to operator++
+# 2308| Type = [LValueReferenceType] iterator &
+# 2308| ValueCategory = prvalue
+# 2308| getQualifier(): [VariableAccess] (__begin)
+# 2308| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2308| ValueCategory = lvalue
+# 2308| getChild(5): [DeclStmt] declaration
+# 2308| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
+# 2308| Type = [Struct] String
+# 2308| getVariable().getInitializer(): [Initializer] initializer for s
+# 2308| getExpr(): [ConstructorCall] call to String
+# 2308| Type = [VoidType] void
+# 2308| ValueCategory = prvalue
+# 2308| getArgument(0): [OverloadedPointerDereferenceExpr] call to operator*
+# 2308| Type = [LValueReferenceType] String &
+# 2308| ValueCategory = prvalue
+# 2308| getQualifier(): [VariableAccess] (__begin)
+# 2308| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2308| ValueCategory = lvalue
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const iterator)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const iterator
#-----| ValueCategory = lvalue
-# 2307| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2307| Type = [LValueReferenceType] const String &
-# 2307| ValueCategory = prvalue
-# 2307| getExpr(): [CStyleCast] (const String)...
-# 2307| Conversion = [GlvalueConversion] glvalue conversion
-# 2307| Type = [SpecifiedType] const String
-# 2307| ValueCategory = lvalue
-# 2307| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
-# 2307| Type = [Struct] String
-# 2307| ValueCategory = lvalue
-# 2307| getStmt(): [BlockStmt] { ... }
-# 2308| getStmt(0): [DeclStmt] declaration
-# 2308| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s2
-# 2308| Type = [Struct] String
-# 2308| getVariable().getInitializer(): [Initializer] initializer for s2
-# 2308| getExpr(): [ConstructorCall] call to String
-# 2308| Type = [VoidType] void
+# 2308| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2308| Type = [LValueReferenceType] const String &
# 2308| ValueCategory = prvalue
-# 2309| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2309| Type = [VoidType] void
-# 2309| ValueCategory = prvalue
-# 2309| getQualifier(): [VariableAccess] s2
+# 2308| getExpr(): [CStyleCast] (const String)...
+# 2308| Conversion = [GlvalueConversion] glvalue conversion
+# 2308| Type = [SpecifiedType] const String
+# 2308| ValueCategory = lvalue
+# 2308| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
+# 2308| Type = [Struct] String
+# 2308| ValueCategory = lvalue
+# 2308| getStmt(): [BlockStmt] { ... }
+# 2309| getStmt(0): [DeclStmt] declaration
+# 2309| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s2
# 2309| Type = [Struct] String
-# 2309| ValueCategory = lvalue
-# 2307| getImplicitDestructorCall(1): [DestructorCall] call to ~String
-# 2307| Type = [VoidType] void
-# 2307| ValueCategory = prvalue
-# 2307| getQualifier(): [VariableAccess] s
-# 2307| Type = [Struct] String
-# 2307| ValueCategory = lvalue
-# 2307| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
-# 2307| Type = [ClassTemplateInstantiation,Struct] iterator
-# 2307| ValueCategory = lvalue
-# 2311| getStmt(3): [ForStmt] for(...;...;...) ...
-# 2311| getInitialization(): [DeclStmt] declaration
-# 2311| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
-# 2311| Type = [Struct] String
-# 2311| getVariable().getInitializer(): [Initializer] initializer for s
-# 2311| getExpr(): [ConstructorCall] call to String
-# 2311| Type = [VoidType] void
-# 2311| ValueCategory = prvalue
-# 2311| getArgument(0): hello
-# 2311| Type = [ArrayType] const char[6]
-# 2311| Value = [StringLiteral] "hello"
-# 2311| ValueCategory = lvalue
-# 2311| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
-# 2311| Type = [PointerType] const char *
-# 2311| ValueCategory = prvalue
-# 2311| getDeclarationEntry(1): [VariableDeclarationEntry] definition of s2
-# 2311| Type = [Struct] String
-# 2311| getVariable().getInitializer(): [Initializer] initializer for s2
-# 2311| getExpr(): [ConstructorCall] call to String
-# 2311| Type = [VoidType] void
-# 2311| ValueCategory = prvalue
-# 2311| getArgument(0): world
-# 2311| Type = [ArrayType] const char[6]
-# 2311| Value = [StringLiteral] "world"
-# 2311| ValueCategory = lvalue
-# 2311| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
-# 2311| Type = [PointerType] const char *
-# 2311| ValueCategory = prvalue
-# 2311| getCondition(): [NEExpr] ... != ...
-# 2311| Type = [BoolType] bool
-# 2311| ValueCategory = prvalue
-# 2311| getLeftOperand(): [VariableAccess] c
-# 2311| Type = [PlainCharType] char
-# 2311| ValueCategory = prvalue(load)
-# 2311| getRightOperand(): [Literal] 0
-# 2311| Type = [IntType] int
-# 2311| Value = [Literal] 0
-# 2311| ValueCategory = prvalue
-# 2311| getLeftOperand().getFullyConverted(): [CStyleCast] (int)...
-# 2311| Conversion = [IntegralConversion] integral conversion
-# 2311| Type = [IntType] int
-# 2311| ValueCategory = prvalue
-# 2311| getUpdate(): [AssignExpr] ... = ...
-# 2311| Type = [PlainCharType] char
-# 2311| ValueCategory = lvalue
-# 2311| getLValue(): [VariableAccess] c
-# 2311| Type = [PlainCharType] char
-# 2311| ValueCategory = lvalue
-# 2311| getRValue(): [FunctionCall] call to pop_back
-# 2311| Type = [PlainCharType] char
-# 2311| ValueCategory = prvalue
-# 2311| getQualifier(): [VariableAccess] s
-# 2311| Type = [Struct] String
-# 2311| ValueCategory = lvalue
-# 2311| getStmt(): [BlockStmt] { ... }
-# 2312| getStmt(0): [ExprStmt] ExprStmt
-# 2312| getExpr(): [AssignExpr] ... = ...
-# 2312| Type = [PlainCharType] char
-# 2312| ValueCategory = lvalue
-# 2312| getLValue(): [VariableAccess] c
-# 2312| Type = [PlainCharType] char
-# 2312| ValueCategory = lvalue
-# 2312| getRValue(): [Literal] 0
-# 2312| Type = [IntType] int
-# 2312| Value = [Literal] 0
+# 2309| getVariable().getInitializer(): [Initializer] initializer for s2
+# 2309| getExpr(): [ConstructorCall] call to String
+# 2309| Type = [VoidType] void
+# 2309| ValueCategory = prvalue
+# 2310| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2310| Type = [VoidType] void
+# 2310| ValueCategory = prvalue
+# 2310| getQualifier(): [VariableAccess] s2
+# 2310| Type = [Struct] String
+# 2310| ValueCategory = lvalue
+# 2308| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
+# 2308| Type = [VoidType] void
+# 2308| ValueCategory = prvalue
+# 2308| getQualifier(): [ReuseExpr] reuse of temporary object
+# 2308| Type = [ClassTemplateInstantiation,Struct] vector
+# 2308| ValueCategory = xvalue
+# 2308| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2308| Type = [ClassTemplateInstantiation,Struct] iterator
+# 2308| ValueCategory = lvalue
+# 2308| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2308| Type = [VoidType] void
+# 2308| ValueCategory = prvalue
+# 2308| getQualifier(): [VariableAccess] s
+# 2308| Type = [Struct] String
+# 2308| ValueCategory = lvalue
+# 2312| getStmt(3): [ForStmt] for(...;...;...) ...
+# 2312| getInitialization(): [DeclStmt] declaration
+# 2312| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
+# 2312| Type = [Struct] String
+# 2312| getVariable().getInitializer(): [Initializer] initializer for s
+# 2312| getExpr(): [ConstructorCall] call to String
+# 2312| Type = [VoidType] void
# 2312| ValueCategory = prvalue
-# 2312| getRValue().getFullyConverted(): [CStyleCast] (char)...
-# 2312| Conversion = [IntegralConversion] integral conversion
-# 2312| Type = [PlainCharType] char
-# 2312| Value = [CStyleCast] 0
+# 2312| getArgument(0): hello
+# 2312| Type = [ArrayType] const char[6]
+# 2312| Value = [StringLiteral] "hello"
+# 2312| ValueCategory = lvalue
+# 2312| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
+# 2312| Type = [PointerType] const char *
+# 2312| ValueCategory = prvalue
+# 2312| getDeclarationEntry(1): [VariableDeclarationEntry] definition of s2
+# 2312| Type = [Struct] String
+# 2312| getVariable().getInitializer(): [Initializer] initializer for s2
+# 2312| getExpr(): [ConstructorCall] call to String
+# 2312| Type = [VoidType] void
# 2312| ValueCategory = prvalue
-# 2311| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2311| Type = [VoidType] void
-# 2311| ValueCategory = prvalue
-# 2311| getQualifier(): [VariableAccess] s2
-# 2311| Type = [Struct] String
-# 2311| ValueCategory = lvalue
-# 2311| getImplicitDestructorCall(1): [DestructorCall] call to ~String
-# 2311| Type = [VoidType] void
-# 2311| ValueCategory = prvalue
-# 2311| getQualifier(): [VariableAccess] s
-# 2311| Type = [Struct] String
-# 2311| ValueCategory = lvalue
-# 2314| getStmt(4): [ReturnStmt] return ...
-# 2316| [TopLevelFunction] void IfDestructors2(bool)
-# 2316| :
-# 2316| getParameter(0): [Parameter] b
-# 2316| Type = [BoolType] bool
-# 2316| getEntryPoint(): [BlockStmt] { ... }
-# 2317| getStmt(0): [IfStmt] if (...) ...
-# 2317| getInitialization(): [DeclStmt] declaration
-# 2317| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
-# 2317| Type = [Struct] String
-# 2317| getVariable().getInitializer(): [Initializer] initializer for s
-# 2317| getExpr(): [ConstructorCall] call to String
-# 2317| Type = [VoidType] void
-# 2317| ValueCategory = prvalue
-# 2317| getArgument(0): hello
-# 2317| Type = [ArrayType] const char[6]
-# 2317| Value = [StringLiteral] "hello"
-# 2317| ValueCategory = lvalue
-# 2317| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
-# 2317| Type = [PointerType] const char *
-# 2317| ValueCategory = prvalue
-# 2317| getCondition(): [VariableAccess] b
-# 2317| Type = [BoolType] bool
-# 2317| ValueCategory = prvalue(load)
-# 2317| getThen(): [BlockStmt] { ... }
-# 2318| getStmt(0): [DeclStmt] declaration
-# 2318| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
-# 2318| Type = [IntType] int
-# 2318| getVariable().getInitializer(): [Initializer] initializer for x
-# 2318| getExpr(): [Literal] 0
-# 2318| Type = [IntType] int
-# 2318| Value = [Literal] 0
+# 2312| getArgument(0): world
+# 2312| Type = [ArrayType] const char[6]
+# 2312| Value = [StringLiteral] "world"
+# 2312| ValueCategory = lvalue
+# 2312| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
+# 2312| Type = [PointerType] const char *
+# 2312| ValueCategory = prvalue
+# 2312| getCondition(): [NEExpr] ... != ...
+# 2312| Type = [BoolType] bool
+# 2312| ValueCategory = prvalue
+# 2312| getLeftOperand(): [VariableAccess] c
+# 2312| Type = [PlainCharType] char
+# 2312| ValueCategory = prvalue(load)
+# 2312| getRightOperand(): [Literal] 0
+# 2312| Type = [IntType] int
+# 2312| Value = [Literal] 0
+# 2312| ValueCategory = prvalue
+# 2312| getLeftOperand().getFullyConverted(): [CStyleCast] (int)...
+# 2312| Conversion = [IntegralConversion] integral conversion
+# 2312| Type = [IntType] int
+# 2312| ValueCategory = prvalue
+# 2312| getUpdate(): [AssignExpr] ... = ...
+# 2312| Type = [PlainCharType] char
+# 2312| ValueCategory = lvalue
+# 2312| getLValue(): [VariableAccess] c
+# 2312| Type = [PlainCharType] char
+# 2312| ValueCategory = lvalue
+# 2312| getRValue(): [FunctionCall] call to pop_back
+# 2312| Type = [PlainCharType] char
+# 2312| ValueCategory = prvalue
+# 2312| getQualifier(): [VariableAccess] s
+# 2312| Type = [Struct] String
+# 2312| ValueCategory = lvalue
+# 2312| getStmt(): [BlockStmt] { ... }
+# 2313| getStmt(0): [ExprStmt] ExprStmt
+# 2313| getExpr(): [AssignExpr] ... = ...
+# 2313| Type = [PlainCharType] char
+# 2313| ValueCategory = lvalue
+# 2313| getLValue(): [VariableAccess] c
+# 2313| Type = [PlainCharType] char
+# 2313| ValueCategory = lvalue
+# 2313| getRValue(): [Literal] 0
+# 2313| Type = [IntType] int
+# 2313| Value = [Literal] 0
+# 2313| ValueCategory = prvalue
+# 2313| getRValue().getFullyConverted(): [CStyleCast] (char)...
+# 2313| Conversion = [IntegralConversion] integral conversion
+# 2313| Type = [PlainCharType] char
+# 2313| Value = [CStyleCast] 0
+# 2313| ValueCategory = prvalue
+# 2312| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2312| Type = [VoidType] void
+# 2312| ValueCategory = prvalue
+# 2312| getQualifier(): [VariableAccess] s2
+# 2312| Type = [Struct] String
+# 2312| ValueCategory = lvalue
+# 2312| getImplicitDestructorCall(1): [DestructorCall] call to ~String
+# 2312| Type = [VoidType] void
+# 2312| ValueCategory = prvalue
+# 2312| getQualifier(): [VariableAccess] s
+# 2312| Type = [Struct] String
+# 2312| ValueCategory = lvalue
+# 2315| getStmt(4): [ReturnStmt] return ...
+# 2317| [TopLevelFunction] void IfDestructors2(bool)
+# 2317| :
+# 2317| getParameter(0): [Parameter] b
+# 2317| Type = [BoolType] bool
+# 2317| getEntryPoint(): [BlockStmt] { ... }
+# 2318| getStmt(0): [IfStmt] if (...) ...
+# 2318| getInitialization(): [DeclStmt] declaration
+# 2318| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
+# 2318| Type = [Struct] String
+# 2318| getVariable().getInitializer(): [Initializer] initializer for s
+# 2318| getExpr(): [ConstructorCall] call to String
+# 2318| Type = [VoidType] void
+# 2318| ValueCategory = prvalue
+# 2318| getArgument(0): hello
+# 2318| Type = [ArrayType] const char[6]
+# 2318| Value = [StringLiteral] "hello"
+# 2318| ValueCategory = lvalue
+# 2318| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
+# 2318| Type = [PointerType] const char *
# 2318| ValueCategory = prvalue
-# 2319| getElse(): [BlockStmt] { ... }
-# 2320| getStmt(0): [DeclStmt] declaration
-# 2320| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
-# 2320| Type = [IntType] int
-# 2320| getVariable().getInitializer(): [Initializer] initializer for y
-# 2320| getExpr(): [Literal] 0
-# 2320| Type = [IntType] int
-# 2320| Value = [Literal] 0
-# 2320| ValueCategory = prvalue
-# 2321| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2321| Type = [VoidType] void
-# 2321| ValueCategory = prvalue
-# 2321| getQualifier(): [VariableAccess] s
-# 2321| Type = [Struct] String
-# 2321| ValueCategory = lvalue
-# 2322| getStmt(1): [ReturnStmt] return ...
-# 2324| [CopyAssignmentOperator] Bool& Bool::operator=(Bool const&)
-# 2324| :
+# 2318| getCondition(): [VariableAccess] b
+# 2318| Type = [BoolType] bool
+# 2318| ValueCategory = prvalue(load)
+# 2318| getThen(): [BlockStmt] { ... }
+# 2319| getStmt(0): [DeclStmt] declaration
+# 2319| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
+# 2319| Type = [IntType] int
+# 2319| getVariable().getInitializer(): [Initializer] initializer for x
+# 2319| getExpr(): [Literal] 0
+# 2319| Type = [IntType] int
+# 2319| Value = [Literal] 0
+# 2319| ValueCategory = prvalue
+# 2320| getElse(): [BlockStmt] { ... }
+# 2321| getStmt(0): [DeclStmt] declaration
+# 2321| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
+# 2321| Type = [IntType] int
+# 2321| getVariable().getInitializer(): [Initializer] initializer for y
+# 2321| getExpr(): [Literal] 0
+# 2321| Type = [IntType] int
+# 2321| Value = [Literal] 0
+# 2321| ValueCategory = prvalue
+# 2322| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2322| Type = [VoidType] void
+# 2322| ValueCategory = prvalue
+# 2322| getQualifier(): [VariableAccess] s
+# 2322| Type = [Struct] String
+# 2322| ValueCategory = lvalue
+# 2323| getStmt(1): [ReturnStmt] return ...
+# 2325| [CopyAssignmentOperator] Bool& Bool::operator=(Bool const&)
+# 2325| :
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const Bool &
-# 2324| [CopyConstructor] void Bool::Bool(Bool const&)
-# 2324| :
+# 2325| [CopyConstructor] void Bool::Bool(Bool const&)
+# 2325| :
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const Bool &
-# 2326| [Constructor] void Bool::Bool(bool)
-# 2326| :
-# 2326| getParameter(0): [Parameter] b_
-# 2326| Type = [BoolType] bool
-# 2327| [ConversionOperator] bool Bool::operator bool()
+# 2327| [Constructor] void Bool::Bool(bool)
# 2327| :
-# 2328| [Destructor] void Bool::~Bool()
+# 2327| getParameter(0): [Parameter] b_
+# 2327| Type = [BoolType] bool
+# 2328| [ConversionOperator] bool Bool::operator bool()
# 2328| :
-# 2331| [TopLevelFunction] void IfDestructors3(bool)
-# 2331| :
-# 2331| getParameter(0): [Parameter] b
-# 2331| Type = [BoolType] bool
-# 2331| getEntryPoint(): [BlockStmt] { ... }
-# 2332| getStmt(0): [IfStmt] if (...) ...
-# 2332| getCondition(): [ConditionDeclExpr] (condition decl)
-# 2332| Type = [BoolType] bool
-# 2332| ValueCategory = prvalue
-# 2332| getChild(0): [FunctionCall] call to operator bool
-# 2332| Type = [BoolType] bool
-# 2332| ValueCategory = prvalue
-# 2332| getQualifier(): [VariableAccess] B
-# 2332| Type = [Class] Bool
-# 2332| ValueCategory = prvalue(load)
-# 2332| getInitializingExpr(): [ConstructorCall] call to Bool
-# 2332| Type = [VoidType] void
-# 2332| ValueCategory = prvalue
-# 2332| getArgument(0): [VariableAccess] b
-# 2332| Type = [BoolType] bool
-# 2332| ValueCategory = prvalue(load)
-# 2332| getThen(): [BlockStmt] { ... }
-# 2333| getStmt(0): [DeclStmt] declaration
-# 2333| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s1
-# 2333| Type = [Struct] String
-# 2333| getVariable().getInitializer(): [Initializer] initializer for s1
-# 2333| getExpr(): [ConstructorCall] call to String
-# 2333| Type = [VoidType] void
-# 2333| ValueCategory = prvalue
-# 2334| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2334| Type = [VoidType] void
-# 2334| ValueCategory = prvalue
-# 2334| getQualifier(): [VariableAccess] s1
+# 2329| [Destructor] void Bool::~Bool()
+# 2329| :
+# 2332| [TopLevelFunction] void IfDestructors3(bool)
+# 2332| :
+# 2332| getParameter(0): [Parameter] b
+# 2332| Type = [BoolType] bool
+# 2332| getEntryPoint(): [BlockStmt] { ... }
+# 2333| getStmt(0): [IfStmt] if (...) ...
+# 2333| getCondition(): [ConditionDeclExpr] (condition decl)
+# 2333| Type = [BoolType] bool
+# 2333| ValueCategory = prvalue
+# 2333| getChild(0): [FunctionCall] call to operator bool
+# 2333| Type = [BoolType] bool
+# 2333| ValueCategory = prvalue
+# 2333| getQualifier(): [VariableAccess] B
+# 2333| Type = [Class] Bool
+# 2333| ValueCategory = prvalue(load)
+# 2333| getInitializingExpr(): [ConstructorCall] call to Bool
+# 2333| Type = [VoidType] void
+# 2333| ValueCategory = prvalue
+# 2333| getArgument(0): [VariableAccess] b
+# 2333| Type = [BoolType] bool
+# 2333| ValueCategory = prvalue(load)
+# 2333| getThen(): [BlockStmt] { ... }
+# 2334| getStmt(0): [DeclStmt] declaration
+# 2334| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s1
# 2334| Type = [Struct] String
-# 2334| ValueCategory = lvalue
-# 2334| getElse(): [BlockStmt] { ... }
-# 2335| getStmt(0): [DeclStmt] declaration
-# 2335| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s2
+# 2334| getVariable().getInitializer(): [Initializer] initializer for s1
+# 2334| getExpr(): [ConstructorCall] call to String
+# 2334| Type = [VoidType] void
+# 2334| ValueCategory = prvalue
+# 2335| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2335| Type = [VoidType] void
+# 2335| ValueCategory = prvalue
+# 2335| getQualifier(): [VariableAccess] s1
# 2335| Type = [Struct] String
-# 2335| getVariable().getInitializer(): [Initializer] initializer for s2
-# 2335| getExpr(): [ConstructorCall] call to String
-# 2335| Type = [VoidType] void
-# 2335| ValueCategory = prvalue
-# 2336| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2336| Type = [VoidType] void
-# 2336| ValueCategory = prvalue
-# 2336| getQualifier(): [VariableAccess] s2
+# 2335| ValueCategory = lvalue
+# 2335| getElse(): [BlockStmt] { ... }
+# 2336| getStmt(0): [DeclStmt] declaration
+# 2336| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s2
# 2336| Type = [Struct] String
-# 2336| ValueCategory = lvalue
-# 2336| getImplicitDestructorCall(0): [DestructorCall] call to ~Bool
-# 2336| Type = [VoidType] void
-# 2336| ValueCategory = prvalue
-# 2336| getQualifier(): [VariableAccess] B
-# 2336| Type = [Class] Bool
-# 2336| ValueCategory = lvalue
-# 2337| getStmt(1): [ReturnStmt] return ...
-# 2339| [TopLevelFunction] void WhileLoopDestructors(bool)
-# 2339| :
-# 2339| getParameter(0): [Parameter] b
-# 2339| Type = [BoolType] bool
-# 2339| getEntryPoint(): [BlockStmt] { ... }
-# 2340| getStmt(0): [BlockStmt] { ... }
-# 2341| getStmt(0): [DeclStmt] declaration
-# 2341| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
-# 2341| Type = [Struct] String
-# 2341| getVariable().getInitializer(): [Initializer] initializer for s
-# 2341| getExpr(): [ConstructorCall] call to String
-# 2341| Type = [VoidType] void
-# 2341| ValueCategory = prvalue
-# 2342| getStmt(1): [WhileStmt] while (...) ...
-# 2342| getCondition(): [VariableAccess] b
-# 2342| Type = [BoolType] bool
-# 2342| ValueCategory = prvalue(load)
-# 2342| getStmt(): [BlockStmt] { ... }
-# 2343| getStmt(0): [ExprStmt] ExprStmt
-# 2343| getExpr(): [AssignExpr] ... = ...
-# 2343| Type = [BoolType] bool
-# 2343| ValueCategory = lvalue
-# 2343| getLValue(): [VariableAccess] b
-# 2343| Type = [BoolType] bool
-# 2343| ValueCategory = lvalue
-# 2343| getRValue(): [Literal] 0
-# 2343| Type = [BoolType] bool
-# 2343| Value = [Literal] 0
-# 2343| ValueCategory = prvalue
-# 2345| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2345| Type = [VoidType] void
-# 2345| ValueCategory = prvalue
-# 2345| getQualifier(): [VariableAccess] s
-# 2345| Type = [Struct] String
-# 2345| ValueCategory = lvalue
-# 2347| getStmt(1): [BlockStmt] { ... }
-# 2348| getStmt(0): [WhileStmt] while (...) ...
-# 2348| getCondition(): [ConditionDeclExpr] (condition decl)
-# 2348| Type = [BoolType] bool
-# 2348| ValueCategory = prvalue
-# 2348| getChild(0): [FunctionCall] call to operator bool
-# 2348| Type = [BoolType] bool
-# 2348| ValueCategory = prvalue
-# 2348| getQualifier(): [VariableAccess] B
-# 2348| Type = [Class] Bool
-# 2348| ValueCategory = prvalue(load)
-# 2348| getInitializingExpr(): [ConstructorCall] call to Bool
-# 2348| Type = [VoidType] void
-# 2348| ValueCategory = prvalue
-# 2348| getArgument(0): [VariableAccess] b
-# 2348| Type = [BoolType] bool
-# 2348| ValueCategory = prvalue(load)
-# 2348| getStmt(): [BlockStmt] { ... }
-# 2349| getStmt(0): [ExprStmt] ExprStmt
-# 2349| getExpr(): [AssignExpr] ... = ...
+# 2336| getVariable().getInitializer(): [Initializer] initializer for s2
+# 2336| getExpr(): [ConstructorCall] call to String
+# 2336| Type = [VoidType] void
+# 2336| ValueCategory = prvalue
+# 2337| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2337| Type = [VoidType] void
+# 2337| ValueCategory = prvalue
+# 2337| getQualifier(): [VariableAccess] s2
+# 2337| Type = [Struct] String
+# 2337| ValueCategory = lvalue
+# 2337| getImplicitDestructorCall(0): [DestructorCall] call to ~Bool
+# 2337| Type = [VoidType] void
+# 2337| ValueCategory = prvalue
+# 2337| getQualifier(): [VariableAccess] B
+# 2337| Type = [Class] Bool
+# 2337| ValueCategory = lvalue
+# 2338| getStmt(1): [ReturnStmt] return ...
+# 2340| [TopLevelFunction] void WhileLoopDestructors(bool)
+# 2340| :
+# 2340| getParameter(0): [Parameter] b
+# 2340| Type = [BoolType] bool
+# 2340| getEntryPoint(): [BlockStmt] { ... }
+# 2341| getStmt(0): [BlockStmt] { ... }
+# 2342| getStmt(0): [DeclStmt] declaration
+# 2342| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
+# 2342| Type = [Struct] String
+# 2342| getVariable().getInitializer(): [Initializer] initializer for s
+# 2342| getExpr(): [ConstructorCall] call to String
+# 2342| Type = [VoidType] void
+# 2342| ValueCategory = prvalue
+# 2343| getStmt(1): [WhileStmt] while (...) ...
+# 2343| getCondition(): [VariableAccess] b
+# 2343| Type = [BoolType] bool
+# 2343| ValueCategory = prvalue(load)
+# 2343| getStmt(): [BlockStmt] { ... }
+# 2344| getStmt(0): [ExprStmt] ExprStmt
+# 2344| getExpr(): [AssignExpr] ... = ...
+# 2344| Type = [BoolType] bool
+# 2344| ValueCategory = lvalue
+# 2344| getLValue(): [VariableAccess] b
+# 2344| Type = [BoolType] bool
+# 2344| ValueCategory = lvalue
+# 2344| getRValue(): [Literal] 0
+# 2344| Type = [BoolType] bool
+# 2344| Value = [Literal] 0
+# 2344| ValueCategory = prvalue
+# 2346| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2346| Type = [VoidType] void
+# 2346| ValueCategory = prvalue
+# 2346| getQualifier(): [VariableAccess] s
+# 2346| Type = [Struct] String
+# 2346| ValueCategory = lvalue
+# 2348| getStmt(1): [BlockStmt] { ... }
+# 2349| getStmt(0): [WhileStmt] while (...) ...
+# 2349| getCondition(): [ConditionDeclExpr] (condition decl)
+# 2349| Type = [BoolType] bool
+# 2349| ValueCategory = prvalue
+# 2349| getChild(0): [FunctionCall] call to operator bool
+# 2349| Type = [BoolType] bool
+# 2349| ValueCategory = prvalue
+# 2349| getQualifier(): [VariableAccess] B
+# 2349| Type = [Class] Bool
+# 2349| ValueCategory = prvalue(load)
+# 2349| getInitializingExpr(): [ConstructorCall] call to Bool
+# 2349| Type = [VoidType] void
+# 2349| ValueCategory = prvalue
+# 2349| getArgument(0): [VariableAccess] b
# 2349| Type = [BoolType] bool
-# 2349| ValueCategory = lvalue
-# 2349| getLValue(): [VariableAccess] b
-# 2349| Type = [BoolType] bool
-# 2349| ValueCategory = lvalue
-# 2349| getRValue(): [Literal] 0
-# 2349| Type = [BoolType] bool
-# 2349| Value = [Literal] 0
-# 2349| ValueCategory = prvalue
-# 2350| getImplicitDestructorCall(0): [DestructorCall] call to ~Bool
-# 2350| Type = [VoidType] void
-# 2350| ValueCategory = prvalue
-# 2350| getQualifier(): [VariableAccess] B
-# 2350| Type = [Class] Bool
+# 2349| ValueCategory = prvalue(load)
+# 2349| getStmt(): [BlockStmt] { ... }
+# 2350| getStmt(0): [ExprStmt] ExprStmt
+# 2350| getExpr(): [AssignExpr] ... = ...
+# 2350| Type = [BoolType] bool
# 2350| ValueCategory = lvalue
-# 2350| getImplicitDestructorCall(0): [DestructorCall] call to ~Bool
-# 2350| Type = [VoidType] void
-# 2350| ValueCategory = prvalue
-# 2350| getQualifier(): [VariableAccess] B
-# 2350| Type = [Class] Bool
-# 2350| ValueCategory = lvalue
-# 2352| getStmt(2): [ReturnStmt] return ...
-# 2354| [TopLevelFunction] void VoidFunc()
-# 2354| :
-# 2354| getEntryPoint(): [BlockStmt] { ... }
-# 2354| getStmt(0): [ReturnStmt] return ...
-# 2356| [TopLevelFunction] void IfReturnDestructors(bool)
-# 2356| :
-# 2356| getParameter(0): [Parameter] b
-# 2356| Type = [BoolType] bool
-# 2356| getEntryPoint(): [BlockStmt] { ... }
-# 2357| getStmt(0): [DeclStmt] declaration
-# 2357| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
-# 2357| Type = [Struct] String
-# 2357| getVariable().getInitializer(): [Initializer] initializer for s
-# 2357| getExpr(): [ConstructorCall] call to String
-# 2357| Type = [VoidType] void
-# 2357| ValueCategory = prvalue
-# 2358| getStmt(1): [IfStmt] if (...) ...
-# 2358| getCondition(): [VariableAccess] b
-# 2358| Type = [BoolType] bool
-# 2358| ValueCategory = prvalue(load)
-# 2358| getThen(): [BlockStmt] { ... }
-# 2359| getStmt(0): [ReturnStmt] return ...
-# 2365| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2365| Type = [VoidType] void
-# 2365| ValueCategory = prvalue
-# 2365| getQualifier(): [VariableAccess] s
-# 2365| Type = [Struct] String
-# 2365| ValueCategory = lvalue
-# 2361| getStmt(2): [IfStmt] if (...) ...
-# 2361| getCondition(): [VariableAccess] b
-# 2361| Type = [BoolType] bool
-# 2361| ValueCategory = prvalue(load)
-# 2361| getThen(): [BlockStmt] { ... }
-# 2362| getStmt(0): [ReturnStmt] return ...
-# 2362| getExpr(): [FunctionCall] call to VoidFunc
-# 2362| Type = [VoidType] void
-# 2362| ValueCategory = prvalue
-# 2365| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2365| Type = [VoidType] void
-# 2365| ValueCategory = prvalue
-# 2365| getQualifier(): [VariableAccess] s
-# 2365| Type = [Struct] String
-# 2365| ValueCategory = lvalue
-# 2364| getStmt(3): [ExprStmt] ExprStmt
-# 2364| getExpr(): [VariableAccess] s
-# 2364| Type = [Struct] String
-# 2364| ValueCategory = lvalue
-# 2365| getStmt(4): [ReturnStmt] return ...
-# 2365| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2365| Type = [VoidType] void
-# 2365| ValueCategory = prvalue
-# 2365| getQualifier(): [VariableAccess] s
-# 2365| Type = [Struct] String
-# 2365| ValueCategory = lvalue
-# 2367| [TopLevelFunction] int IfReturnDestructors3(bool)
-# 2367| :
-# 2367| getParameter(0): [Parameter] b
-# 2367| Type = [BoolType] bool
-# 2367| getEntryPoint(): [BlockStmt] { ... }
-# 2368| getStmt(0): [DeclStmt] declaration
-# 2368| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
-# 2368| Type = [Struct] String
-# 2368| getVariable().getInitializer(): [Initializer] initializer for s
-# 2368| getExpr(): [ConstructorCall] call to String
-# 2368| Type = [VoidType] void
-# 2368| ValueCategory = prvalue
-# 2369| getStmt(1): [IfStmt] if (...) ...
-# 2369| getCondition(): [VariableAccess] b
-# 2369| Type = [BoolType] bool
-# 2369| ValueCategory = prvalue(load)
-# 2369| getThen(): [BlockStmt] { ... }
-# 2370| getStmt(0): [ReturnStmt] return ...
-# 2370| getExpr(): [Literal] 1
-# 2370| Type = [IntType] int
-# 2370| Value = [Literal] 1
-# 2370| ValueCategory = prvalue
-# 2373| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2373| Type = [VoidType] void
-# 2373| ValueCategory = prvalue
-# 2373| getQualifier(): [VariableAccess] s
-# 2373| Type = [Struct] String
-# 2373| ValueCategory = lvalue
-# 2372| getStmt(2): [ReturnStmt] return ...
-# 2372| getExpr(): [Literal] 0
-# 2372| Type = [IntType] int
-# 2372| Value = [Literal] 0
-# 2372| ValueCategory = prvalue
-# 2373| getImplicitDestructorCall(0): [DestructorCall] call to ~String
-# 2373| Type = [VoidType] void
+# 2350| getLValue(): [VariableAccess] b
+# 2350| Type = [BoolType] bool
+# 2350| ValueCategory = lvalue
+# 2350| getRValue(): [Literal] 0
+# 2350| Type = [BoolType] bool
+# 2350| Value = [Literal] 0
+# 2350| ValueCategory = prvalue
+# 2351| getImplicitDestructorCall(0): [DestructorCall] call to ~Bool
+# 2351| Type = [VoidType] void
+# 2351| ValueCategory = prvalue
+# 2351| getQualifier(): [VariableAccess] B
+# 2351| Type = [Class] Bool
+# 2351| ValueCategory = lvalue
+# 2351| getImplicitDestructorCall(0): [DestructorCall] call to ~Bool
+# 2351| Type = [VoidType] void
+# 2351| ValueCategory = prvalue
+# 2351| getQualifier(): [VariableAccess] B
+# 2351| Type = [Class] Bool
+# 2351| ValueCategory = lvalue
+# 2353| getStmt(2): [ReturnStmt] return ...
+# 2355| [TopLevelFunction] void VoidFunc()
+# 2355| :
+# 2355| getEntryPoint(): [BlockStmt] { ... }
+# 2355| getStmt(0): [ReturnStmt] return ...
+# 2357| [TopLevelFunction] void IfReturnDestructors(bool)
+# 2357| :
+# 2357| getParameter(0): [Parameter] b
+# 2357| Type = [BoolType] bool
+# 2357| getEntryPoint(): [BlockStmt] { ... }
+# 2358| getStmt(0): [DeclStmt] declaration
+# 2358| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
+# 2358| Type = [Struct] String
+# 2358| getVariable().getInitializer(): [Initializer] initializer for s
+# 2358| getExpr(): [ConstructorCall] call to String
+# 2358| Type = [VoidType] void
+# 2358| ValueCategory = prvalue
+# 2359| getStmt(1): [IfStmt] if (...) ...
+# 2359| getCondition(): [VariableAccess] b
+# 2359| Type = [BoolType] bool
+# 2359| ValueCategory = prvalue(load)
+# 2359| getThen(): [BlockStmt] { ... }
+# 2360| getStmt(0): [ReturnStmt] return ...
+# 2366| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2366| Type = [VoidType] void
+# 2366| ValueCategory = prvalue
+# 2366| getQualifier(): [VariableAccess] s
+# 2366| Type = [Struct] String
+# 2366| ValueCategory = lvalue
+# 2362| getStmt(2): [IfStmt] if (...) ...
+# 2362| getCondition(): [VariableAccess] b
+# 2362| Type = [BoolType] bool
+# 2362| ValueCategory = prvalue(load)
+# 2362| getThen(): [BlockStmt] { ... }
+# 2363| getStmt(0): [ReturnStmt] return ...
+# 2363| getExpr(): [FunctionCall] call to VoidFunc
+# 2363| Type = [VoidType] void
+# 2363| ValueCategory = prvalue
+# 2366| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2366| Type = [VoidType] void
+# 2366| ValueCategory = prvalue
+# 2366| getQualifier(): [VariableAccess] s
+# 2366| Type = [Struct] String
+# 2366| ValueCategory = lvalue
+# 2365| getStmt(3): [ExprStmt] ExprStmt
+# 2365| getExpr(): [VariableAccess] s
+# 2365| Type = [Struct] String
+# 2365| ValueCategory = lvalue
+# 2366| getStmt(4): [ReturnStmt] return ...
+# 2366| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2366| Type = [VoidType] void
+# 2366| ValueCategory = prvalue
+# 2366| getQualifier(): [VariableAccess] s
+# 2366| Type = [Struct] String
+# 2366| ValueCategory = lvalue
+# 2368| [TopLevelFunction] int IfReturnDestructors3(bool)
+# 2368| :
+# 2368| getParameter(0): [Parameter] b
+# 2368| Type = [BoolType] bool
+# 2368| getEntryPoint(): [BlockStmt] { ... }
+# 2369| getStmt(0): [DeclStmt] declaration
+# 2369| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
+# 2369| Type = [Struct] String
+# 2369| getVariable().getInitializer(): [Initializer] initializer for s
+# 2369| getExpr(): [ConstructorCall] call to String
+# 2369| Type = [VoidType] void
+# 2369| ValueCategory = prvalue
+# 2370| getStmt(1): [IfStmt] if (...) ...
+# 2370| getCondition(): [VariableAccess] b
+# 2370| Type = [BoolType] bool
+# 2370| ValueCategory = prvalue(load)
+# 2370| getThen(): [BlockStmt] { ... }
+# 2371| getStmt(0): [ReturnStmt] return ...
+# 2371| getExpr(): [Literal] 1
+# 2371| Type = [IntType] int
+# 2371| Value = [Literal] 1
+# 2371| ValueCategory = prvalue
+# 2374| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2374| Type = [VoidType] void
+# 2374| ValueCategory = prvalue
+# 2374| getQualifier(): [VariableAccess] s
+# 2374| Type = [Struct] String
+# 2374| ValueCategory = lvalue
+# 2373| getStmt(2): [ReturnStmt] return ...
+# 2373| getExpr(): [Literal] 0
+# 2373| Type = [IntType] int
+# 2373| Value = [Literal] 0
# 2373| ValueCategory = prvalue
-# 2373| getQualifier(): [VariableAccess] s
-# 2373| Type = [Struct] String
-# 2373| ValueCategory = lvalue
-# 2375| [TopLevelFunction] void VoidReturnDestructors()
-# 2375| :
-# 2375| getEntryPoint(): [BlockStmt] { ... }
-# 2376| getStmt(0): [DeclStmt] declaration
-# 2376| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
-# 2376| Type = [Struct] String
-# 2376| getVariable().getInitializer(): [Initializer] initializer for s
-# 2376| getExpr(): [ConstructorCall] call to String
-# 2376| Type = [VoidType] void
-# 2376| ValueCategory = prvalue
-# 2377| getStmt(1): [ReturnStmt] return ...
-# 2377| getExpr(): [FunctionCall] call to VoidFunc
-# 2377| Type = [VoidType] void
-# 2377| ValueCategory = prvalue
-# 2378| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2374| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2374| Type = [VoidType] void
+# 2374| ValueCategory = prvalue
+# 2374| getQualifier(): [VariableAccess] s
+# 2374| Type = [Struct] String
+# 2374| ValueCategory = lvalue
+# 2376| [TopLevelFunction] void VoidReturnDestructors()
+# 2376| :
+# 2376| getEntryPoint(): [BlockStmt] { ... }
+# 2377| getStmt(0): [DeclStmt] declaration
+# 2377| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
+# 2377| Type = [Struct] String
+# 2377| getVariable().getInitializer(): [Initializer] initializer for s
+# 2377| getExpr(): [ConstructorCall] call to String
+# 2377| Type = [VoidType] void
+# 2377| ValueCategory = prvalue
+# 2378| getStmt(1): [ReturnStmt] return ...
+# 2378| getExpr(): [FunctionCall] call to VoidFunc
# 2378| Type = [VoidType] void
# 2378| ValueCategory = prvalue
-# 2378| getQualifier(): [VariableAccess] s
-# 2378| Type = [Struct] String
-# 2378| ValueCategory = lvalue
-# 2381| [CopyAssignmentOperator] return_routine_type::HasVoidToIntFunc& return_routine_type::HasVoidToIntFunc::operator=(return_routine_type::HasVoidToIntFunc const&)
-# 2381| :
+# 2379| getImplicitDestructorCall(0): [DestructorCall] call to ~String
+# 2379| Type = [VoidType] void
+# 2379| ValueCategory = prvalue
+# 2379| getQualifier(): [VariableAccess] s
+# 2379| Type = [Struct] String
+# 2379| ValueCategory = lvalue
+# 2382| [CopyAssignmentOperator] return_routine_type::HasVoidToIntFunc& return_routine_type::HasVoidToIntFunc::operator=(return_routine_type::HasVoidToIntFunc const&)
+# 2382| :
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const HasVoidToIntFunc &
-# 2381| [MoveAssignmentOperator] return_routine_type::HasVoidToIntFunc& return_routine_type::HasVoidToIntFunc::operator=(return_routine_type::HasVoidToIntFunc&&)
-# 2381| :
+# 2382| [MoveAssignmentOperator] return_routine_type::HasVoidToIntFunc& return_routine_type::HasVoidToIntFunc::operator=(return_routine_type::HasVoidToIntFunc&&)
+# 2382| :
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] HasVoidToIntFunc &&
-# 2383| [MemberFunction] void return_routine_type::HasVoidToIntFunc::VoidToInt(int)
-# 2383| :
-# 2383| getParameter(0): [Parameter] (unnamed parameter 0)
-# 2383| Type = [IntType] int
-# 2388| [TopLevelFunction] return_routine_type::VoidToIntMemberFunc return_routine_type::GetVoidToIntFunc()
-# 2388| :
-# 2389| getEntryPoint(): [BlockStmt] { ... }
-# 2390| getStmt(0): [ReturnStmt] return ...
-# 2390| getExpr(): [FunctionAccess] VoidToInt
-# 2390| Type = [RoutineType] ..()(..)
-# 2390| ValueCategory = prvalue
-# 2395| [TopLevelFunction] int small_operation_should_not_be_constant_folded()
-# 2395| :
-# 2395| getEntryPoint(): [BlockStmt] { ... }
-# 2396| getStmt(0): [ReturnStmt] return ...
-# 2396| getExpr(): [BitwiseXorExpr] ... ^ ...
-# 2396| Type = [IntType] int
-# 2396| Value = [BitwiseXorExpr] 3
-# 2396| ValueCategory = prvalue
-# 2396| getLeftOperand(): [Literal] 1
-# 2396| Type = [IntType] int
-# 2396| Value = [Literal] 1
-# 2396| ValueCategory = prvalue
-# 2396| getRightOperand(): [Literal] 2
-# 2396| Type = [IntType] int
-# 2396| Value = [Literal] 2
-# 2396| ValueCategory = prvalue
-# 2406| [TopLevelFunction] int large_operation_should_be_constant_folded()
-# 2406| :
-# 2406| getEntryPoint(): [BlockStmt] { ... }
-# 2407| getStmt(0): [ReturnStmt] return ...
-# 2407| getExpr(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [BitwiseXorExpr] ... ^ ...
-# 2407| Type = [IntType] int
-# 2407| Value = [BitwiseXorExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand(): [Literal] 1
-# 2407| Type = [IntType] int
-# 2407| Value = [Literal] 1
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2407| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
-# 2407| Type = [IntType] int
-# 2407| Value = [ParenthesisExpr] 0
-# 2407| ValueCategory = prvalue
-# 2410| [TopLevelFunction] void initialization_with_temp_destructor()
-# 2410| :
-# 2410| getEntryPoint(): [BlockStmt] { ... }
-# 2411| getStmt(0): [IfStmt] if (...) ...
-# 2411| getCondition(): [ConditionDeclExpr] (condition decl)
-# 2411| Type = [BoolType] bool
-# 2411| ValueCategory = prvalue
-# 2411| getVariableAccess(): [VariableAccess] x
-# 2411| Type = [PlainCharType] char
-# 2411| ValueCategory = prvalue(load)
-# 2411| getInitializingExpr(): [FunctionCall] call to get_x
-# 2411| Type = [PlainCharType] char
-# 2411| ValueCategory = prvalue
-# 2411| getQualifier(): [ConstructorCall] call to ClassWithDestructor
-# 2411| Type = [VoidType] void
-# 2411| ValueCategory = prvalue
-# 2411| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2411| Type = [VoidType] void
-# 2411| ValueCategory = prvalue
-# 2411| getQualifier(): [ReuseExpr] reuse of temporary object
-# 2411| Type = [Class] ClassWithDestructor
-# 2411| ValueCategory = xvalue
-# 2411| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
-# 2411| Type = [Class] ClassWithDestructor
-# 2411| ValueCategory = prvalue(load)
-# 2411| getVariableAccess().getFullyConverted(): [CStyleCast] (bool)...
-# 2411| Conversion = [BoolConversion] conversion to bool
-# 2411| Type = [BoolType] bool
-# 2411| ValueCategory = prvalue
-# 2412| getThen(): [ExprStmt] ExprStmt
-# 2412| getExpr(): [PostfixIncrExpr] ... ++
+# 2384| [MemberFunction] void return_routine_type::HasVoidToIntFunc::VoidToInt(int)
+# 2384| :
+# 2384| getParameter(0): [Parameter] (unnamed parameter 0)
+# 2384| Type = [IntType] int
+# 2389| [TopLevelFunction] return_routine_type::VoidToIntMemberFunc return_routine_type::GetVoidToIntFunc()
+# 2389| :
+# 2390| getEntryPoint(): [BlockStmt] { ... }
+# 2391| getStmt(0): [ReturnStmt] return ...
+# 2391| getExpr(): [FunctionAccess] VoidToInt
+# 2391| Type = [RoutineType] ..()(..)
+# 2391| ValueCategory = prvalue
+# 2396| [TopLevelFunction] int small_operation_should_not_be_constant_folded()
+# 2396| :
+# 2396| getEntryPoint(): [BlockStmt] { ... }
+# 2397| getStmt(0): [ReturnStmt] return ...
+# 2397| getExpr(): [BitwiseXorExpr] ... ^ ...
+# 2397| Type = [IntType] int
+# 2397| Value = [BitwiseXorExpr] 3
+# 2397| ValueCategory = prvalue
+# 2397| getLeftOperand(): [Literal] 1
+# 2397| Type = [IntType] int
+# 2397| Value = [Literal] 1
+# 2397| ValueCategory = prvalue
+# 2397| getRightOperand(): [Literal] 2
+# 2397| Type = [IntType] int
+# 2397| Value = [Literal] 2
+# 2397| ValueCategory = prvalue
+# 2407| [TopLevelFunction] int large_operation_should_be_constant_folded()
+# 2407| :
+# 2407| getEntryPoint(): [BlockStmt] { ... }
+# 2408| getStmt(0): [ReturnStmt] return ...
+# 2408| getExpr(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [BitwiseXorExpr] ... ^ ...
+# 2408| Type = [IntType] int
+# 2408| Value = [BitwiseXorExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand(): [Literal] 1
+# 2408| Type = [IntType] int
+# 2408| Value = [Literal] 1
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2408| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
+# 2408| Type = [IntType] int
+# 2408| Value = [ParenthesisExpr] 0
+# 2408| ValueCategory = prvalue
+# 2411| [TopLevelFunction] void initialization_with_temp_destructor()
+# 2411| :
+# 2411| getEntryPoint(): [BlockStmt] { ... }
+# 2412| getStmt(0): [IfStmt] if (...) ...
+# 2412| getCondition(): [ConditionDeclExpr] (condition decl)
+# 2412| Type = [BoolType] bool
+# 2412| ValueCategory = prvalue
+# 2412| getVariableAccess(): [VariableAccess] x
# 2412| Type = [PlainCharType] char
+# 2412| ValueCategory = prvalue(load)
+# 2412| getInitializingExpr(): [FunctionCall] call to get_x
+# 2412| Type = [PlainCharType] char
+# 2412| ValueCategory = prvalue
+# 2412| getQualifier(): [ConstructorCall] call to ClassWithDestructor
+# 2412| Type = [VoidType] void
+# 2412| ValueCategory = prvalue
+# 2412| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2412| Type = [VoidType] void
+# 2412| ValueCategory = prvalue
+# 2412| getQualifier(): [ReuseExpr] reuse of temporary object
+# 2412| Type = [Class] ClassWithDestructor
+# 2412| ValueCategory = xvalue
+# 2412| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2412| Type = [Class] ClassWithDestructor
+# 2412| ValueCategory = prvalue(load)
+# 2412| getVariableAccess().getFullyConverted(): [CStyleCast] (bool)...
+# 2412| Conversion = [BoolConversion] conversion to bool
+# 2412| Type = [BoolType] bool
# 2412| ValueCategory = prvalue
-# 2412| getOperand(): [VariableAccess] x
-# 2412| Type = [PlainCharType] char
-# 2412| ValueCategory = lvalue
-# 2414| getStmt(1): [IfStmt] if (...) ...
-# 2414| getInitialization(): [DeclStmt] declaration
-# 2414| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
-# 2414| Type = [PlainCharType] char
-# 2414| getVariable().getInitializer(): [Initializer] initializer for x
-# 2414| getExpr(): [FunctionCall] call to get_x
-# 2414| Type = [PlainCharType] char
-# 2414| ValueCategory = prvalue
-# 2414| getQualifier(): [ConstructorCall] call to ClassWithDestructor
-# 2414| Type = [VoidType] void
-# 2414| ValueCategory = prvalue
-# 2414| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2414| Type = [VoidType] void
-# 2414| ValueCategory = prvalue
-# 2414| getQualifier(): [ReuseExpr] reuse of temporary object
-# 2414| Type = [Class] ClassWithDestructor
-# 2414| ValueCategory = xvalue
-# 2414| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
-# 2414| Type = [Class] ClassWithDestructor
-# 2414| ValueCategory = prvalue(load)
-# 2414| getCondition(): [VariableAccess] x
-# 2414| Type = [PlainCharType] char
-# 2414| ValueCategory = prvalue(load)
-# 2415| getThen(): [ExprStmt] ExprStmt
-# 2415| getExpr(): [PostfixIncrExpr] ... ++
+# 2413| getThen(): [ExprStmt] ExprStmt
+# 2413| getExpr(): [PostfixIncrExpr] ... ++
+# 2413| Type = [PlainCharType] char
+# 2413| ValueCategory = prvalue
+# 2413| getOperand(): [VariableAccess] x
+# 2413| Type = [PlainCharType] char
+# 2413| ValueCategory = lvalue
+# 2415| getStmt(1): [IfStmt] if (...) ...
+# 2415| getInitialization(): [DeclStmt] declaration
+# 2415| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 2415| Type = [PlainCharType] char
-# 2415| ValueCategory = prvalue
-# 2415| getOperand(): [VariableAccess] x
-# 2415| Type = [PlainCharType] char
-# 2415| ValueCategory = lvalue
-# 2414| getCondition().getFullyConverted(): [CStyleCast] (bool)...
-# 2414| Conversion = [BoolConversion] conversion to bool
-# 2414| Type = [BoolType] bool
-# 2414| ValueCategory = prvalue
-# 2417| getStmt(2): [ConstexprIfStmt] if constexpr (...) ...
-# 2417| getInitialization(): [DeclStmt] declaration
-# 2417| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
-# 2417| Type = [PlainCharType] char
-# 2417| getVariable().getInitializer(): [Initializer] initializer for x
-# 2417| getExpr(): [FunctionCall] call to get_x
-# 2417| Type = [PlainCharType] char
-# 2417| ValueCategory = prvalue
-# 2417| getQualifier(): [ConstructorCall] call to ClassWithDestructor
-# 2417| Type = [VoidType] void
-# 2417| ValueCategory = prvalue
-# 2417| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2417| Type = [VoidType] void
-# 2417| ValueCategory = prvalue
-# 2417| getQualifier(): [ReuseExpr] reuse of temporary object
-# 2417| Type = [Class] ClassWithDestructor
-# 2417| ValueCategory = xvalue
-# 2417| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
-# 2417| Type = [Class] ClassWithDestructor
-# 2417| ValueCategory = prvalue(load)
-# 2417| getCondition(): [VariableAccess] initialization_with_destructor_bool
-# 2417| Type = [BoolType] bool
-# 2417| Value = [VariableAccess] 1
-# 2417| ValueCategory = prvalue(load)
-# 2418| getThen(): [ExprStmt] ExprStmt
-# 2418| getExpr(): [PostfixIncrExpr] ... ++
+# 2415| getVariable().getInitializer(): [Initializer] initializer for x
+# 2415| getExpr(): [FunctionCall] call to get_x
+# 2415| Type = [PlainCharType] char
+# 2415| ValueCategory = prvalue
+# 2415| getQualifier(): [ConstructorCall] call to ClassWithDestructor
+# 2415| Type = [VoidType] void
+# 2415| ValueCategory = prvalue
+# 2415| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2415| Type = [VoidType] void
+# 2415| ValueCategory = prvalue
+# 2415| getQualifier(): [ReuseExpr] reuse of temporary object
+# 2415| Type = [Class] ClassWithDestructor
+# 2415| ValueCategory = xvalue
+# 2415| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2415| Type = [Class] ClassWithDestructor
+# 2415| ValueCategory = prvalue(load)
+# 2415| getCondition(): [VariableAccess] x
+# 2415| Type = [PlainCharType] char
+# 2415| ValueCategory = prvalue(load)
+# 2416| getThen(): [ExprStmt] ExprStmt
+# 2416| getExpr(): [PostfixIncrExpr] ... ++
+# 2416| Type = [PlainCharType] char
+# 2416| ValueCategory = prvalue
+# 2416| getOperand(): [VariableAccess] x
+# 2416| Type = [PlainCharType] char
+# 2416| ValueCategory = lvalue
+# 2415| getCondition().getFullyConverted(): [CStyleCast] (bool)...
+# 2415| Conversion = [BoolConversion] conversion to bool
+# 2415| Type = [BoolType] bool
+# 2415| ValueCategory = prvalue
+# 2418| getStmt(2): [ConstexprIfStmt] if constexpr (...) ...
+# 2418| getInitialization(): [DeclStmt] declaration
+# 2418| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 2418| Type = [PlainCharType] char
-# 2418| ValueCategory = prvalue
-# 2418| getOperand(): [VariableAccess] x
-# 2418| Type = [PlainCharType] char
-# 2418| ValueCategory = lvalue
-# 2420| getStmt(3): [SwitchStmt] switch (...) ...
-# 2420| getExpr(): [ConditionDeclExpr] (condition decl)
-# 2420| Type = [IntType] int
-# 2420| ValueCategory = prvalue
-# 2420| getVariableAccess(): [VariableAccess] x
-# 2420| Type = [PlainCharType] char
-# 2420| ValueCategory = prvalue(load)
-# 2420| getInitializingExpr(): [FunctionCall] call to get_x
-# 2420| Type = [PlainCharType] char
-# 2420| ValueCategory = prvalue
-# 2420| getQualifier(): [ConstructorCall] call to ClassWithDestructor
-# 2420| Type = [VoidType] void
-# 2420| ValueCategory = prvalue
-# 2420| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2420| Type = [VoidType] void
-# 2420| ValueCategory = prvalue
-# 2420| getQualifier(): [ReuseExpr] reuse of temporary object
-# 2420| Type = [Class] ClassWithDestructor
-# 2420| ValueCategory = xvalue
-# 2420| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
-# 2420| Type = [Class] ClassWithDestructor
-# 2420| ValueCategory = prvalue(load)
-# 2420| getVariableAccess().getFullyConverted(): [CStyleCast] (int)...
-# 2420| Conversion = [IntegralConversion] integral conversion
-# 2420| Type = [IntType] int
-# 2420| ValueCategory = prvalue
-# 2420| getStmt(): [BlockStmt] { ... }
-# 2421| getStmt(0): [SwitchCase] case ...:
-# 2421| getExpr(): [CharLiteral] 97
-# 2421| Type = [PlainCharType] char
-# 2421| Value = [CharLiteral] 97
+# 2418| getVariable().getInitializer(): [Initializer] initializer for x
+# 2418| getExpr(): [FunctionCall] call to get_x
+# 2418| Type = [PlainCharType] char
+# 2418| ValueCategory = prvalue
+# 2418| getQualifier(): [ConstructorCall] call to ClassWithDestructor
+# 2418| Type = [VoidType] void
+# 2418| ValueCategory = prvalue
+# 2418| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2418| Type = [VoidType] void
+# 2418| ValueCategory = prvalue
+# 2418| getQualifier(): [ReuseExpr] reuse of temporary object
+# 2418| Type = [Class] ClassWithDestructor
+# 2418| ValueCategory = xvalue
+# 2418| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2418| Type = [Class] ClassWithDestructor
+# 2418| ValueCategory = prvalue(load)
+# 2418| getCondition(): [VariableAccess] initialization_with_destructor_bool
+# 2418| Type = [BoolType] bool
+# 2418| Value = [VariableAccess] 1
+# 2418| ValueCategory = prvalue(load)
+# 2419| getThen(): [ExprStmt] ExprStmt
+# 2419| getExpr(): [PostfixIncrExpr] ... ++
+# 2419| Type = [PlainCharType] char
+# 2419| ValueCategory = prvalue
+# 2419| getOperand(): [VariableAccess] x
+# 2419| Type = [PlainCharType] char
+# 2419| ValueCategory = lvalue
+# 2421| getStmt(3): [SwitchStmt] switch (...) ...
+# 2421| getExpr(): [ConditionDeclExpr] (condition decl)
+# 2421| Type = [IntType] int
+# 2421| ValueCategory = prvalue
+# 2421| getVariableAccess(): [VariableAccess] x
+# 2421| Type = [PlainCharType] char
+# 2421| ValueCategory = prvalue(load)
+# 2421| getInitializingExpr(): [FunctionCall] call to get_x
+# 2421| Type = [PlainCharType] char
+# 2421| ValueCategory = prvalue
+# 2421| getQualifier(): [ConstructorCall] call to ClassWithDestructor
+# 2421| Type = [VoidType] void
# 2421| ValueCategory = prvalue
-# 2421| getExpr().getFullyConverted(): [CStyleCast] (int)...
-# 2421| Conversion = [IntegralConversion] integral conversion
-# 2421| Type = [IntType] int
-# 2421| Value = [CStyleCast] 97
+# 2421| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2421| Type = [VoidType] void
# 2421| ValueCategory = prvalue
-# 2422| getStmt(1): [ExprStmt] ExprStmt
-# 2422| getExpr(): [PostfixIncrExpr] ... ++
+# 2421| getQualifier(): [ReuseExpr] reuse of temporary object
+# 2421| Type = [Class] ClassWithDestructor
+# 2421| ValueCategory = xvalue
+# 2421| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2421| Type = [Class] ClassWithDestructor
+# 2421| ValueCategory = prvalue(load)
+# 2421| getVariableAccess().getFullyConverted(): [CStyleCast] (int)...
+# 2421| Conversion = [IntegralConversion] integral conversion
+# 2421| Type = [IntType] int
+# 2421| ValueCategory = prvalue
+# 2421| getStmt(): [BlockStmt] { ... }
+# 2422| getStmt(0): [SwitchCase] case ...:
+# 2422| getExpr(): [CharLiteral] 97
# 2422| Type = [PlainCharType] char
+# 2422| Value = [CharLiteral] 97
+# 2422| ValueCategory = prvalue
+# 2422| getExpr().getFullyConverted(): [CStyleCast] (int)...
+# 2422| Conversion = [IntegralConversion] integral conversion
+# 2422| Type = [IntType] int
+# 2422| Value = [CStyleCast] 97
# 2422| ValueCategory = prvalue
-# 2422| getOperand(): [VariableAccess] x
-# 2422| Type = [PlainCharType] char
-# 2422| ValueCategory = lvalue
-# 2425| getStmt(4): [SwitchStmt] switch (...) ...
-# 2425| getInitialization(): [DeclStmt] declaration
-# 2425| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
-# 2425| Type = [PlainCharType] char
-# 2425| getVariable().getInitializer(): [Initializer] initializer for x
-# 2425| getExpr(): [FunctionCall] call to get_x
-# 2425| Type = [PlainCharType] char
-# 2425| ValueCategory = prvalue
-# 2425| getQualifier(): [ConstructorCall] call to ClassWithDestructor
-# 2425| Type = [VoidType] void
-# 2425| ValueCategory = prvalue
-# 2425| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2425| Type = [VoidType] void
-# 2425| ValueCategory = prvalue
-# 2425| getQualifier(): [ReuseExpr] reuse of temporary object
-# 2425| Type = [Class] ClassWithDestructor
-# 2425| ValueCategory = xvalue
-# 2425| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
-# 2425| Type = [Class] ClassWithDestructor
-# 2425| ValueCategory = prvalue(load)
-# 2425| getExpr(): [VariableAccess] x
-# 2425| Type = [PlainCharType] char
-# 2425| ValueCategory = prvalue(load)
-# 2425| getStmt(): [BlockStmt] { ... }
-# 2426| getStmt(0): [SwitchCase] case ...:
-# 2426| getExpr(): [CharLiteral] 97
-# 2426| Type = [PlainCharType] char
-# 2426| Value = [CharLiteral] 97
-# 2426| ValueCategory = prvalue
-# 2426| getExpr().getFullyConverted(): [CStyleCast] (int)...
-# 2426| Conversion = [IntegralConversion] integral conversion
-# 2426| Type = [IntType] int
-# 2426| Value = [CStyleCast] 97
-# 2426| ValueCategory = prvalue
-# 2427| getStmt(1): [ExprStmt] ExprStmt
-# 2427| getExpr(): [PostfixIncrExpr] ... ++
+# 2423| getStmt(1): [ExprStmt] ExprStmt
+# 2423| getExpr(): [PostfixIncrExpr] ... ++
+# 2423| Type = [PlainCharType] char
+# 2423| ValueCategory = prvalue
+# 2423| getOperand(): [VariableAccess] x
+# 2423| Type = [PlainCharType] char
+# 2423| ValueCategory = lvalue
+# 2426| getStmt(4): [SwitchStmt] switch (...) ...
+# 2426| getInitialization(): [DeclStmt] declaration
+# 2426| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
+# 2426| Type = [PlainCharType] char
+# 2426| getVariable().getInitializer(): [Initializer] initializer for x
+# 2426| getExpr(): [FunctionCall] call to get_x
+# 2426| Type = [PlainCharType] char
+# 2426| ValueCategory = prvalue
+# 2426| getQualifier(): [ConstructorCall] call to ClassWithDestructor
+# 2426| Type = [VoidType] void
+# 2426| ValueCategory = prvalue
+# 2426| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2426| Type = [VoidType] void
+# 2426| ValueCategory = prvalue
+# 2426| getQualifier(): [ReuseExpr] reuse of temporary object
+# 2426| Type = [Class] ClassWithDestructor
+# 2426| ValueCategory = xvalue
+# 2426| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2426| Type = [Class] ClassWithDestructor
+# 2426| ValueCategory = prvalue(load)
+# 2426| getExpr(): [VariableAccess] x
+# 2426| Type = [PlainCharType] char
+# 2426| ValueCategory = prvalue(load)
+# 2426| getStmt(): [BlockStmt] { ... }
+# 2427| getStmt(0): [SwitchCase] case ...:
+# 2427| getExpr(): [CharLiteral] 97
# 2427| Type = [PlainCharType] char
+# 2427| Value = [CharLiteral] 97
# 2427| ValueCategory = prvalue
-# 2427| getOperand(): [VariableAccess] x
-# 2427| Type = [PlainCharType] char
-# 2427| ValueCategory = lvalue
-# 2425| getExpr().getFullyConverted(): [CStyleCast] (int)...
-# 2425| Conversion = [IntegralConversion] integral conversion
-# 2425| Type = [IntType] int
-# 2425| ValueCategory = prvalue
-# 2430| getStmt(5): [RangeBasedForStmt] for(...:...) ...
-# 2430| getInitialization(): [DeclStmt] declaration
-# 2430| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
-# 2430| Type = [PlainCharType] char
-# 2430| getVariable().getInitializer(): [Initializer] initializer for x
-# 2430| getExpr(): [FunctionCall] call to get_x
-# 2430| Type = [PlainCharType] char
-# 2430| ValueCategory = prvalue
-# 2430| getQualifier(): [ConstructorCall] call to ClassWithDestructor
-# 2430| Type = [VoidType] void
-# 2430| ValueCategory = prvalue
-# 2430| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
-# 2430| Type = [VoidType] void
-# 2430| ValueCategory = prvalue
-# 2430| getQualifier(): [ReuseExpr] reuse of temporary object
-# 2430| Type = [Class] ClassWithDestructor
-# 2430| ValueCategory = xvalue
-# 2430| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
-# 2430| Type = [Class] ClassWithDestructor
-# 2430| ValueCategory = prvalue(load)
-# 2430| getChild(1): [DeclStmt] declaration
-# 2430| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
-# 2430| Type = [RValueReferenceType] vector &&
+# 2427| getExpr().getFullyConverted(): [CStyleCast] (int)...
+# 2427| Conversion = [IntegralConversion] integral conversion
+# 2427| Type = [IntType] int
+# 2427| Value = [CStyleCast] 97
+# 2427| ValueCategory = prvalue
+# 2428| getStmt(1): [ExprStmt] ExprStmt
+# 2428| getExpr(): [PostfixIncrExpr] ... ++
+# 2428| Type = [PlainCharType] char
+# 2428| ValueCategory = prvalue
+# 2428| getOperand(): [VariableAccess] x
+# 2428| Type = [PlainCharType] char
+# 2428| ValueCategory = lvalue
+# 2426| getExpr().getFullyConverted(): [CStyleCast] (int)...
+# 2426| Conversion = [IntegralConversion] integral conversion
+# 2426| Type = [IntType] int
+# 2426| ValueCategory = prvalue
+# 2431| getStmt(5): [RangeBasedForStmt] for(...:...) ...
+# 2431| getInitialization(): [DeclStmt] declaration
+# 2431| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
+# 2431| Type = [PlainCharType] char
+# 2431| getVariable().getInitializer(): [Initializer] initializer for x
+# 2431| getExpr(): [FunctionCall] call to get_x
+# 2431| Type = [PlainCharType] char
+# 2431| ValueCategory = prvalue
+# 2431| getQualifier(): [ConstructorCall] call to ClassWithDestructor
+# 2431| Type = [VoidType] void
+# 2431| ValueCategory = prvalue
+# 2431| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
+# 2431| Type = [VoidType] void
+# 2431| ValueCategory = prvalue
+# 2431| getQualifier(): [ReuseExpr] reuse of temporary object
+# 2431| Type = [Class] ClassWithDestructor
+# 2431| ValueCategory = xvalue
+# 2431| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2431| Type = [Class] ClassWithDestructor
+# 2431| ValueCategory = prvalue(load)
+# 2431| getChild(1): [DeclStmt] declaration
+# 2431| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
+# 2431| Type = [RValueReferenceType] vector &&
#-----| getVariable().getInitializer(): [Initializer] initializer for (__range)
-# 2430| getExpr(): [ConstructorCall] call to vector
-# 2430| Type = [VoidType] void
-# 2430| ValueCategory = prvalue
-# 2430| getArgument(0): [VariableAccess] x
-# 2430| Type = [PlainCharType] char
-# 2430| ValueCategory = prvalue(load)
-# 2430| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2430| Type = [LValueReferenceType] vector &
-# 2430| ValueCategory = prvalue
-# 2430| getExpr(): [TemporaryObjectExpr] temporary object
-# 2430| Type = [ClassTemplateInstantiation,Struct] vector
-# 2430| ValueCategory = xvalue
-# 2430| getBeginEndDeclaration(): [DeclStmt] declaration
-# 2430| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
-# 2430| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2431| getExpr(): [ConstructorCall] call to vector
+# 2431| Type = [VoidType] void
+# 2431| ValueCategory = prvalue
+# 2431| getArgument(0): [VariableAccess] x
+# 2431| Type = [PlainCharType] char
+# 2431| ValueCategory = prvalue(load)
+# 2431| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2431| Type = [LValueReferenceType] vector &
+# 2431| ValueCategory = prvalue
+# 2431| getExpr(): [TemporaryObjectExpr] temporary object
+# 2431| Type = [ClassTemplateInstantiation,Struct] vector
+# 2431| ValueCategory = xvalue
+# 2431| getBeginEndDeclaration(): [DeclStmt] declaration
+# 2431| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
+# 2431| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
#-----| getVariable().getInitializer(): [Initializer] initializer for (__begin)
-# 2430| getExpr(): [FunctionCall] call to begin
-# 2430| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
-# 2430| ValueCategory = prvalue
-# 2430| getQualifier(): [VariableAccess] (__range)
-# 2430| Type = [RValueReferenceType] vector &&
-# 2430| ValueCategory = prvalue(load)
+# 2431| getExpr(): [FunctionCall] call to begin
+# 2431| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
+# 2431| ValueCategory = prvalue
+# 2431| getQualifier(): [VariableAccess] (__range)
+# 2431| Type = [RValueReferenceType] vector &&
+# 2431| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const vector