Skip to content

Commit 464f66b

Browse files
authored
Merge pull request #1287 from nickrolfe/fold
C++: support for fold expressions
2 parents 3905cf7 + 50c901d commit 464f66b

File tree

7 files changed

+4255
-3923
lines changed

7 files changed

+4255
-3923
lines changed

change-notes/1.21/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@
3333
- Additional support for definition by reference has been added to the `semmle.code.cpp.dataflow.TaintTracking` library.
3434
- The taint tracking library now includes taint-specific edges for functions modeled in `semmle.code.cpp.models.interfaces.DataFlow`.
3535
- The taint tracking library adds flow through library functions that are modeled in `semmle.code.cpp.models.interfaces.Taint`. Queries can add subclasses of `TaintFunction` to specify additional flow.
36+
- There is a new `FoldExpr` class, representing C++17 fold expressions.

cpp/ql/src/semmle/code/cpp/exprs/Expr.qll

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,61 @@ class NoExceptExpr extends Expr, @noexceptexpr {
964964
}
965965
}
966966

967+
/**
968+
* A C++17 fold expression. This will only appear in an uninstantiated template; any instantiations
969+
* of the template will instead contain the sequence of expressions given by expanding the fold.
970+
*/
971+
class FoldExpr extends Expr, @foldexpr {
972+
override string toString() {
973+
exists(string op |
974+
op = this.getOperatorString() and
975+
if this.isUnaryFold()
976+
then
977+
if this.isLeftFold()
978+
then result = "( ... " + op + " pack )"
979+
else result = "( pack " + op + " ... )"
980+
else
981+
if this.isLeftFold()
982+
then result = "( init " + op + " ... " + op + " pack )"
983+
else result = "( pack " + op + " ... " + op + " init )"
984+
)
985+
}
986+
987+
/** Gets the binary operator used in this fold expression, as a string. */
988+
string getOperatorString() { fold(underlyingElement(this), result, _) }
989+
990+
/** Holds if this is a left-fold expression. */
991+
predicate isLeftFold() { fold(underlyingElement(this), _, true) }
992+
993+
/** Holds if this is a right-fold expression. */
994+
predicate isRightFold() { fold(underlyingElement(this), _, false) }
995+
996+
/** Holds if this is a unary fold expression. */
997+
predicate isUnaryFold() { getNumChild() = 1 }
998+
999+
/** Holds if this is a binary fold expression. */
1000+
predicate isBinaryFold() { getNumChild() = 2 }
1001+
1002+
/**
1003+
* Gets the child expression containing the unexpanded parameter pack.
1004+
*/
1005+
Expr getPackExpr() {
1006+
this.isUnaryFold() and
1007+
result = getChild(0)
1008+
or
1009+
this.isBinaryFold() and
1010+
if this.isRightFold() then result = getChild(0) else result = getChild(1)
1011+
}
1012+
1013+
/**
1014+
* If this is a binary fold, gets the expression representing the initial value.
1015+
*/
1016+
Expr getInitExpr() {
1017+
this.isBinaryFold() and
1018+
if this.isRightFold() then result = getChild(1) else result = getChild(0)
1019+
}
1020+
}
1021+
9671022
/**
9681023
* Holds if `child` is the `n`th child of `parent` in an alternative syntax
9691024
* tree that has `Conversion`s as part of the tree.

cpp/ql/src/semmlecode.cpp.dbscheme

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,7 @@ case @expr.kind of
14321432
| 129 = @new_array_expr
14331433
// ... 130 @objc_array_literal deprecated
14341434
// ... 131 @objc_dictionary_literal deprecated
1435+
| 132 = @foldexpr
14351436
// ...
14361437
| 200 = @ctordirectinit
14371438
| 201 = @ctorvirtualinit
@@ -1579,6 +1580,12 @@ lambda_capture(
15791580
@addressable = @function | @variable ;
15801581
@accessible = @addressable | @enumconstant ;
15811582

1583+
fold(
1584+
int expr: @foldexpr ref,
1585+
string operator: string ref,
1586+
boolean is_left_fold: boolean ref
1587+
);
1588+
15821589
stmts(
15831590
unique int id: @stmt,
15841591
int kind: int ref,

0 commit comments

Comments
 (0)