Skip to content

Commit 17a453b

Browse files
authored
Merge pull request #21126 from jketema/subscript
C++: Add predicates to support C++23 multidimensional subscript operators
2 parents 991d30f + 72f1aa9 commit 17a453b

File tree

9 files changed

+113
-7
lines changed

9 files changed

+113
-7
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: feature
3+
---
4+
* Predicates `getArrayOffset/1` and `getAnArrayOffset` have been added to the `OverloadedArrayExpr` class to support C++23 multidimensional subscript operators.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: deprecated
3+
---
4+
* The `OverloadedArrayExpr::getArrayOffset/0` predicate has been deprecated. Use `OverloadedArrayExpr::getArrayOffset/1` and `OverloadedArrayExpr::getAnArrayOffset` instead.

cpp/ql/lib/semmle/code/cpp/PrintAST.qll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,10 +1050,10 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
10501050
expr.(Call).getQualifier() = ele and
10511051
pred = "getQualifier()"
10521052
or
1053-
// OverloadedArrayExpr::getArrayBase/0 and OverloadedArrayExpr::getArrayOffset/0 also consider arguments, and are already handled below.
1053+
// OverloadedArrayExpr::getArrayBase/0 and OverloadedArrayExpr::getArrayOffset/1 also consider arguments, and are already handled below.
10541054
exists(int n, Expr arg | expr.(Call).getArgument(n) = arg |
10551055
not expr.(OverloadedArrayExpr).getArrayBase() = arg and
1056-
not expr.(OverloadedArrayExpr).getArrayOffset() = arg and
1056+
not expr.(OverloadedArrayExpr).getAnArrayOffset() = arg and
10571057
arg = ele and
10581058
pred = "getArgument(" + n.toString() + ")"
10591059
)
@@ -1062,7 +1062,10 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
10621062
or
10631063
expr.(OverloadedArrayExpr).getArrayBase() = ele and pred = "getArrayBase()"
10641064
or
1065-
expr.(OverloadedArrayExpr).getArrayOffset() = ele and pred = "getArrayOffset()"
1065+
exists(int n |
1066+
expr.(OverloadedArrayExpr).getArrayOffset(n) = ele and
1067+
pred = "getArrayOffset(" + n.toString() + ")"
1068+
)
10661069
or
10671070
// OverloadedPointerDereferenceExpr::getExpr/0 also considers qualifiers, and is already handled above for all Call classes.
10681071
not expr.(OverloadedPointerDereferenceExpr).getQualifier() =

cpp/ql/lib/semmle/code/cpp/exprs/Call.qll

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,10 +387,23 @@ class OverloadedArrayExpr extends FunctionCall {
387387

388388
/**
389389
* Gets the expression giving the index.
390+
*
391+
* DEPRECATED: Use getArrayOffset/1 instead.
392+
*/
393+
deprecated Expr getArrayOffset() { result = this.getArrayOffset(0) }
394+
395+
/**
396+
* Gets the expression giving the nth index.
390397
*/
391-
Expr getArrayOffset() {
392-
if exists(this.getQualifier()) then result = this.getChild(0) else result = this.getChild(1)
398+
Expr getArrayOffset(int n) {
399+
n >= 0 and
400+
if exists(this.getQualifier()) then result = this.getChild(n) else result = this.getChild(n + 1)
393401
}
402+
403+
/**
404+
* Gets an expression giving an index.
405+
*/
406+
Expr getAnArrayOffset() { result = this.getArrayOffset(_) }
394407
}
395408

396409
/**

cpp/ql/src/jsf/lib/section_4_21_Operators/AV_Rule_166.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class SizeofImpureExprOperator extends SizeofExprOperator {
1313
not e.(OverloadedPointerDereferenceExpr).getExpr().isPure() and
1414
not exists(OverloadedArrayExpr op | op = e |
1515
op.getArrayBase().isPure() and
16-
op.getArrayOffset().isPure()
16+
forall(Expr offset | offset = op.getAnArrayOffset() | offset.isPure())
1717
)
1818
)
1919
}

cpp/ql/test/library-tests/ir/ir/PrintAST.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24309,7 +24309,7 @@ ir.cpp:
2430924309
# 2727| getArrayBase(): [VariableAccess] x
2431024310
# 2727| Type = [SpecifiedType] const WithBracketOperator
2431124311
# 2727| ValueCategory = lvalue
24312-
# 2727| getArrayOffset(): [VariableAccess] i
24312+
# 2727| getArrayOffset(0): [VariableAccess] i
2431324313
# 2727| Type = [IntType] int
2431424314
# 2727| ValueCategory = prvalue(load)
2431524315
# 2727| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#-----| [CopyAssignmentOperator] __va_list_tag& __va_list_tag::operator=(__va_list_tag const&)
2+
#-----| <params>:
3+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
4+
#-----| Type = [LValueReferenceType] const __va_list_tag &
5+
#-----| [MoveAssignmentOperator] __va_list_tag& __va_list_tag::operator=(__va_list_tag&&)
6+
#-----| <params>:
7+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
8+
#-----| Type = [RValueReferenceType] __va_list_tag &&
9+
test.cpp:
10+
# 3| [CopyAssignmentOperator] S& S::operator=(S const&)
11+
# 3| <params>:
12+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
13+
#-----| Type = [LValueReferenceType] const S &
14+
# 3| [MoveAssignmentOperator] S& S::operator=(S&&)
15+
# 3| <params>:
16+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
17+
#-----| Type = [RValueReferenceType] S &&
18+
# 5| [MemberFunction] int S::operator[](int, int)
19+
# 5| <params>:
20+
# 5| getParameter(0): [Parameter] i
21+
# 5| Type = [IntType] int
22+
# 5| getParameter(1): [Parameter] j
23+
# 5| Type = [IntType] int
24+
# 5| getEntryPoint(): [BlockStmt] { ... }
25+
# 6| getStmt(0): [ReturnStmt] return ...
26+
# 6| getExpr(): [ArrayExpr] access to array
27+
# 6| Type = [IntType] int
28+
# 6| ValueCategory = prvalue(load)
29+
# 6| getArrayBase(): [ArrayExpr] access to array
30+
# 6| Type = [ArrayType] int[2]
31+
# 6| ValueCategory = lvalue
32+
# 6| getArrayBase(): [ImplicitThisFieldAccess,PointerFieldAccess] xs
33+
# 6| Type = [ArrayType] int[2][2]
34+
# 6| ValueCategory = lvalue
35+
# 6| getQualifier(): [ThisExpr] this
36+
# 6| Type = [PointerType] S *
37+
# 6| ValueCategory = prvalue(load)
38+
# 6| getArrayOffset(): [VariableAccess] i
39+
# 6| Type = [IntType] int
40+
# 6| ValueCategory = prvalue(load)
41+
#-----| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
42+
#-----| Type = [PointerType] int(*)[2]
43+
#-----| ValueCategory = prvalue
44+
# 6| getArrayOffset(): [VariableAccess] j
45+
# 6| Type = [IntType] int
46+
# 6| ValueCategory = prvalue(load)
47+
# 6| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
48+
# 6| Type = [IntPointerType] int *
49+
# 6| ValueCategory = prvalue
50+
# 10| [TopLevelFunction] int foo(S)
51+
# 10| <params>:
52+
# 10| getParameter(0): [Parameter] s
53+
# 10| Type = [Struct] S
54+
# 10| getEntryPoint(): [BlockStmt] { ... }
55+
# 11| getStmt(0): [ReturnStmt] return ...
56+
# 11| getExpr(): [OverloadedArrayExpr] call to operator[]
57+
# 11| Type = [IntType] int
58+
# 11| ValueCategory = prvalue
59+
# 11| getArrayBase(): [VariableAccess] s
60+
# 11| Type = [Struct] S
61+
# 11| ValueCategory = lvalue
62+
# 11| getArrayOffset(0): [Literal] 1
63+
# 11| Type = [IntType] int
64+
# 11| Value = [Literal] 1
65+
# 11| ValueCategory = prvalue
66+
# 11| getArrayOffset(1): [Literal] 2
67+
# 11| Type = [IntType] int
68+
# 11| Value = [Literal] 2
69+
# 11| ValueCategory = prvalue
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
semmle/code/cpp/PrintAST.ql
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// semmle-extractor-options: -std=c++23
2+
3+
struct S {
4+
int xs[2][2];
5+
int operator[](int i, int j) {
6+
return xs[i][j];
7+
}
8+
};
9+
10+
int foo(S s) {
11+
return s[1, 2];
12+
}

0 commit comments

Comments
 (0)