Merge pull request #1287 from nickrolfe/fold

C++: support for fold expressions
This commit is contained in:
ian-semmle
2019-05-02 15:39:10 +01:00
committed by GitHub
7 changed files with 4490 additions and 4158 deletions

View File

@@ -33,3 +33,4 @@
- Additional support for definition by reference has been added to the `semmle.code.cpp.dataflow.TaintTracking` library.
- The taint tracking library now includes taint-specific edges for functions modeled in `semmle.code.cpp.models.interfaces.DataFlow`.
- 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.
- There is a new `FoldExpr` class, representing C++17 fold expressions.

View File

@@ -964,6 +964,61 @@ class NoExceptExpr extends Expr, @noexceptexpr {
}
}
/**
* A C++17 fold expression. This will only appear in an uninstantiated template; any instantiations
* of the template will instead contain the sequence of expressions given by expanding the fold.
*/
class FoldExpr extends Expr, @foldexpr {
override string toString() {
exists(string op |
op = this.getOperatorString() and
if this.isUnaryFold()
then
if this.isLeftFold()
then result = "( ... " + op + " pack )"
else result = "( pack " + op + " ... )"
else
if this.isLeftFold()
then result = "( init " + op + " ... " + op + " pack )"
else result = "( pack " + op + " ... " + op + " init )"
)
}
/** Gets the binary operator used in this fold expression, as a string. */
string getOperatorString() { fold(underlyingElement(this), result, _) }
/** Holds if this is a left-fold expression. */
predicate isLeftFold() { fold(underlyingElement(this), _, true) }
/** Holds if this is a right-fold expression. */
predicate isRightFold() { fold(underlyingElement(this), _, false) }
/** Holds if this is a unary fold expression. */
predicate isUnaryFold() { getNumChild() = 1 }
/** Holds if this is a binary fold expression. */
predicate isBinaryFold() { getNumChild() = 2 }
/**
* Gets the child expression containing the unexpanded parameter pack.
*/
Expr getPackExpr() {
this.isUnaryFold() and
result = getChild(0)
or
this.isBinaryFold() and
if this.isRightFold() then result = getChild(0) else result = getChild(1)
}
/**
* If this is a binary fold, gets the expression representing the initial value.
*/
Expr getInitExpr() {
this.isBinaryFold() and
if this.isRightFold() then result = getChild(1) else result = getChild(0)
}
}
/**
* Holds if `child` is the `n`th child of `parent` in an alternative syntax
* tree that has `Conversion`s as part of the tree.

View File

@@ -1432,6 +1432,7 @@ case @expr.kind of
| 129 = @new_array_expr
// ... 130 @objc_array_literal deprecated
// ... 131 @objc_dictionary_literal deprecated
| 132 = @foldexpr
// ...
| 200 = @ctordirectinit
| 201 = @ctorvirtualinit
@@ -1579,6 +1580,12 @@ lambda_capture(
@addressable = @function | @variable ;
@accessible = @addressable | @enumconstant ;
fold(
int expr: @foldexpr ref,
string operator: string ref,
boolean is_left_fold: boolean ref
);
stmts(
unique int id: @stmt,
int kind: int ref,

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
// semmle-extractor-options: --edg --c++17
template<typename ...Args>
int sum(Args&&... args) {
return (args + ...);
}
template<typename ...Args>
int product(Args&&... args) {
return (... * args);
}
template<typename ...Args>
bool all(Args&&... args) {
return (args && ... && true);
}
template<typename ...Args>
bool any(Args&&... args) {
return (false || ... || args);
}
void f() {
int x = sum(1, 2, 3, 4, 5);
int y = product(2, 4, 6, 8);
bool a = all(true, true, false, true);
bool b = any(false, true, false, false);
}

View File

@@ -0,0 +1,4 @@
| fold.cpp:5:10:5:21 | ( pack + ... ) | + | fold.cpp:5:11:5:14 | args | <no init> |
| fold.cpp:10:10:10:21 | ( ... * pack ) | * | fold.cpp:10:17:10:20 | args | <no init> |
| fold.cpp:15:10:15:30 | ( pack && ... && init ) | && | fold.cpp:15:11:15:14 | args | 1 |
| fold.cpp:20:10:20:31 | ( init \|\| ... \|\| pack ) | \|\| | fold.cpp:20:27:20:30 | args | 0 |

View File

@@ -0,0 +1,7 @@
import cpp
from FoldExpr fe, Expr pack, string init
where
pack = fe.getPackExpr() and
if exists(fe.getInitExpr()) then init = fe.getInitExpr().toString() else init = "<no init>"
select fe, fe.getOperatorString(), pack, init