@@ -17,6 +17,7 @@ import cpp
1717import codingstandards.cpp.autosar
1818import codingstandards.cpp.TrivialType
1919import codingstandards.cpp.SideEffect
20+ import semmle.code.cpp.controlflow.SSA
2021
2122predicate isZeroInitializable ( Variable v ) {
2223 not exists ( v .getInitializer ( ) .getExpr ( ) ) and
@@ -33,6 +34,78 @@ predicate isTypeZeroInitializable(Type t) {
3334 t .getUnderlyingType ( ) instanceof ArrayType
3435}
3536
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+
36109from Variable v
37110where
38111 not isExcluded ( v , ConstPackage:: variableMissingConstexprQuery ( ) ) and
46119 (
47120 v .getInitializer ( ) .getExpr ( ) .isConstant ( )
48121 or
49- v . getInitializer ( ) . getExpr ( ) . ( Call ) . getTarget ( ) .isConstexpr ( )
122+ any ( Call call | isCompileTimeEvaluated ( call ) ) = v . getInitializer ( ) .getExpr ( )
50123 or
51124 isZeroInitializable ( v )
52125 or
0 commit comments