diff --git a/cpp/ql/lib/change-notes/2024-12-20-sizeof-pack.md b/cpp/ql/lib/change-notes/2024-12-20-sizeof-pack.md new file mode 100644 index 00000000000..cf613501479 --- /dev/null +++ b/cpp/ql/lib/change-notes/2024-12-20-sizeof-pack.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* A new classes `SizeofPackExprOperator` and `SizeofPackTypeOperator` were introduced, which represent the C++ `sizeof...` operator taking an expression and a type argument, respectively. diff --git a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll index 7a6307898ef..492788202b4 100644 --- a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll @@ -1056,6 +1056,8 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) or expr.(SizeofExprOperator).getExprOperand() = ele and pred = "getExprOperand()" or + expr.(SizeofPackExprOperator).getExprOperand() = ele and pred = "getExprOperand()" + or expr.(StmtExpr).getStmt() = ele and pred = "getStmt()" or expr.(ThrowExpr).getExpr() = ele and pred = "getExpr()" diff --git a/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll index 85293cc7313..83364e422eb 100644 --- a/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll @@ -684,7 +684,8 @@ class TypeidOperator extends Expr, @type_id { } /** - * A C++11 `sizeof...` expression which determines the size of a template parameter pack. + * A C++11 `sizeof...` expression which determines the size of a template + * parameter pack. * * This expression only appears in templates themselves - in any actual * instantiations, "sizeof...(x)" will be replaced by its integer value. @@ -694,15 +695,56 @@ class TypeidOperator extends Expr, @type_id { * ``` */ class SizeofPackOperator extends Expr, @sizeof_pack { - override string toString() { result = "sizeof...(...)" } - - override string getAPrimaryQlClass() { result = "SizeofPackOperator" } - override predicate mayBeImpure() { none() } override predicate mayBeGloballyImpure() { none() } } +/** + * A C++11 `sizeof...` expression which determines the size of a template + * parameter pack and whose operand is an expression. + * + * This expression only appears in templates themselves - in any actual + * instantiations, "sizeof...(x)" will be replaced by its integer value. + * ``` + * template < typename... T > + * int count ( T &&... t ) { return sizeof... ( t ); } + * ``` + */ +class SizeofPackExprOperator extends SizeofPackOperator { + SizeofPackExprOperator() { exists(this.getChild(0)) } + + override string getAPrimaryQlClass() { result = "SizeofPackExprOperator" } + + /** Gets the contained expression. */ + Expr getExprOperand() { result = this.getChild(0) } + + override string toString() { result = "sizeof...()" } +} + +/** + * A C++11 `sizeof...` expression which determines the size of a template + * parameter pack and whose operand is an type name or a template template + * parameter. + * + * This expression only appears in templates themselves - in any actual + * instantiations, "sizeof...(x)" will be replaced by its integer value. + * ``` + * template < typename... T > + * int count ( T &&... t ) { return sizeof... ( T ); } + * ``` + */ +class SizeofPackTypeOperator extends SizeofPackOperator { + SizeofPackTypeOperator() { sizeof_bind(underlyingElement(this), _) } + + override string getAPrimaryQlClass() { result = "SizeofPackTypeOperator" } + + /** Gets the contained type. */ + Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) } + + override string toString() { result = "sizeof...(" + this.getTypeOperand().getName() + ")" } +} + /** * A C/C++ sizeof expression. */