C++: Share the constant initializer detection

Since this code is shared between the AST CFG and the IR construction,
it seems right to have only one copy. That copy lives on a new class
`StaticStorageDurationVariable`, which may prove useful on its own.
This commit is contained in:
Jonas Jensen
2020-03-10 16:33:08 +01:00
parent 0cd3eb7b7e
commit 5e01b4b858
3 changed files with 45 additions and 35 deletions

View File

@@ -366,6 +366,47 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
}
}
/**
* A variable whose contents always have static storage duration. This can be a
* global variable, a namespace variable, a static local variable, or a static
* member variable.
*/
class StaticStorageDurationVariable extends Variable {
StaticStorageDurationVariable() {
this instanceof GlobalOrNamespaceVariable
or
this.(LocalVariable).isStatic()
or
this.(MemberVariable).isStatic()
}
/**
* Holds if the initializer for this variable is evaluated at compile time.
*/
predicate hasConstantInitialization() {
not runtimeExprInStaticInitializer(this.getInitializer().getExpr())
}
}
/**
* Holds if `e` is an expression in a static initializer that must be evaluated
* at run time. This predicate computes "is non-const" instead of "is const"
* since computing "is const" for an aggregate literal with many children would
* either involve recursion through `forall` on those children or an iteration
* through the rank numbers of the children, both of which can be slow.
*/
private predicate runtimeExprInStaticInitializer(Expr e) {
inStaticInitializer(e) and
if e instanceof AggregateLiteral
then runtimeExprInStaticInitializer(e.getAChild())
else not e.getFullyConverted().isConstant()
}
/** Holds if `e` is part of the initializer of a `StaticStorageDurationVariable`. */
private predicate inStaticInitializer(Expr e) {
exists(StaticStorageDurationVariable var | e.getParent+() = var.getInitializer())
}
/**
* A C/C++ variable which has global scope or namespace scope. For example the
* variables `a` and `b` in the following code:

View File

@@ -443,8 +443,7 @@ private Node getControlOrderChildSparse(Node n, int i) {
private predicate skipInitializer(Initializer init) {
exists(LocalVariable local |
init = local.getInitializer() and
local.isStatic() and
not runtimeExprInStaticInitializer(init.getExpr())
local.(StaticStorageDurationVariable).hasConstantInitialization()
)
}

View File

@@ -31,37 +31,6 @@ private Element getRealParent(Expr expr) {
*/
predicate isIRConstant(Expr expr) { exists(expr.getValue()) }
/**
* Holds if the expression in this initializer is evaluated at compile time.
*/
private predicate skipInitializer(Initializer init) {
exists(LocalVariable local |
init = local.getInitializer() and
local.isStatic() and
not runtimeExprInStaticInitializer(init.getExpr())
)
}
/**
* Holds if `e` is an expression in a static initializer that must be evaluated
* at run time. This predicate computes "is non-const" instead of "is const" in
* order to avoid recursion through forall.
*/
private predicate runtimeExprInStaticInitializer(Expr e) {
inStaticInitializer(e) and
if e instanceof AggregateLiteral
then runtimeExprInStaticInitializer(e.getAChild())
else not e.getFullyConverted().isConstant()
}
/** Holds if `e` is part of the initializer of a local static variable. */
private predicate inStaticInitializer(Expr e) {
exists(LocalVariable local |
local.isStatic() and
e.getParent+() = local.getInitializer()
)
}
// Pulled out to work around QL-796
private predicate isOrphan(Expr expr) { not exists(getRealParent(expr)) }
@@ -83,8 +52,9 @@ private predicate ignoreExprAndDescendants(Expr expr) {
or
// Only translate the initializer of a static local if it uses run-time data.
// Otherwise the initializer does not run in function scope.
exists(Initializer init |
skipInitializer(init) and
exists(Initializer init, StaticStorageDurationVariable var |
init = var.getInitializer() and
var.hasConstantInitialization() and
expr = init.getExpr().getFullyConverted()
)
or