@@ -17,6 +17,7 @@ import cpp
17
17
import codingstandards.cpp.autosar
18
18
import codingstandards.cpp.TrivialType
19
19
import codingstandards.cpp.SideEffect
20
+ import semmle.code.cpp.controlflow.SSA
20
21
21
22
predicate isZeroInitializable ( Variable v ) {
22
23
not exists ( v .getInitializer ( ) .getExpr ( ) ) and
@@ -33,6 +34,78 @@ predicate isTypeZeroInitializable(Type t) {
33
34
t .getUnderlyingType ( ) instanceof ArrayType
34
35
}
35
36
37
+ /**
38
+ * An optimized set of expressions used to determine the flow through constexpr variables.
39
+ */
40
+ class VariableAccessOrCallOrLiteral extends Expr {
41
+ VariableAccessOrCallOrLiteral ( ) {
42
+ this instanceof VariableAccess or
43
+ this instanceof Call or
44
+ this instanceof Literal
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Holds if the value of source flows through compile time evaluated variables to target.
50
+ */
51
+ predicate flowsThroughConstExprVariables (
52
+ VariableAccessOrCallOrLiteral source , VariableAccessOrCallOrLiteral target
53
+ ) {
54
+ (
55
+ source = target
56
+ or
57
+ source != target and
58
+ exists ( SsaDefinition intermediateDef , StackVariable intermediate |
59
+ intermediateDef .getAVariable ( ) .getFunction ( ) = source .getEnclosingFunction ( ) and
60
+ intermediateDef .getAVariable ( ) .getFunction ( ) = target .getEnclosingFunction ( ) and
61
+ intermediateDef .getAVariable ( ) = intermediate and
62
+ intermediate .isConstexpr ( )
63
+ |
64
+ DataFlow:: localExprFlow ( source , intermediateDef .getDefiningValue ( intermediate ) ) and
65
+ flowsThroughConstExprVariables ( intermediateDef .getAUse ( intermediate ) , target )
66
+ )
67
+ )
68
+ }
69
+
70
+ /*
71
+ * Returns true if the given call may be evaluated at compile time and is compile time evaluated because
72
+ * all its arguments are compile time evaluated and its default values are compile time evaluated.
73
+ */
74
+
75
+ predicate isCompileTimeEvaluated ( Call call ) {
76
+ // 1. The call may be evaluated at compile time, because it is constexpr, and
77
+ call .getTarget ( ) .isConstexpr ( ) and
78
+ // 2. all its arguments are compile time evaluated, and
79
+ forall ( DataFlow:: Node ultimateArgSource , DataFlow:: Node argSource |
80
+ argSource = DataFlow:: exprNode ( call .getAnArgument ( ) ) and
81
+ DataFlow:: localFlow ( ultimateArgSource , argSource ) and
82
+ not DataFlow:: localFlowStep ( _, ultimateArgSource )
83
+ |
84
+ (
85
+ ultimateArgSource .asExpr ( ) instanceof Literal
86
+ or
87
+ any ( Call c | isCompileTimeEvaluated ( c ) ) = ultimateArgSource .asExpr ( )
88
+ ) and
89
+ // If the ultimate argument source is not the same as the argument source, then it must flow through
90
+ // constexpr variables.
91
+ (
92
+ ultimateArgSource != argSource
93
+ implies
94
+ flowsThroughConstExprVariables ( ultimateArgSource .asExpr ( ) , argSource .asExpr ( ) )
95
+ )
96
+ ) and
97
+ // 3. all the default values used are compile time evaluated.
98
+ forall ( Expr defaultValue , Parameter parameterUsingDefaultValue , int idx |
99
+ parameterUsingDefaultValue = call .getTarget ( ) .getParameter ( idx ) and
100
+ not exists ( call .getArgument ( idx ) ) and
101
+ parameterUsingDefaultValue .getAnAssignedValue ( ) = defaultValue
102
+ |
103
+ defaultValue instanceof Literal
104
+ or
105
+ any ( Call c | isCompileTimeEvaluated ( c ) ) = defaultValue
106
+ )
107
+ }
108
+
36
109
from Variable v
37
110
where
38
111
not isExcluded ( v , ConstPackage:: variableMissingConstexprQuery ( ) ) and
46
119
(
47
120
v .getInitializer ( ) .getExpr ( ) .isConstant ( )
48
121
or
49
- v . getInitializer ( ) . getExpr ( ) . ( Call ) . getTarget ( ) .isConstexpr ( )
122
+ any ( Call call | isCompileTimeEvaluated ( call ) ) = v . getInitializer ( ) .getExpr ( )
50
123
or
51
124
isZeroInitializable ( v )
52
125
or
0 commit comments