Skip to content

Commit bba7f16

Browse files
C++: Simplify TranslatedExpr hierarchy a bit
I introduced some unnecessary base classes in the `TranslatedExpr` hierarchy with a previous commit. This commit refactors the hierarchy a bit to align with the following high-level description: `TranslatedExpr` represents a translated piece of an `Expr`. Each `Expr` has exactly one `TranslatedCoreExpr`, which produces the result of that `Expr` ignoring any lvalue-to-rvalue conversion on its result. If an lvalue-to-rvalue converison is present, there is an additional `TranslatedLoad` for that `Expr` to do the conversion. For higher-level `Expr`s like `NewExpr`, there can also be additional `TranslatedExpr`s to represent the sub-operations within the overall `Expr`, such as the allocator call.
1 parent b9a8293 commit bba7f16

File tree

3 files changed

+116
-71
lines changed

3 files changed

+116
-71
lines changed

cpp/ql/src/semmle/code/cpp/ir/internal/TranslatedElement.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ predicate ignoreLoad(Expr expr) {
164164

165165
newtype TTranslatedElement =
166166
// An expression that is not being consumed as a condition
167-
TTranslatedNonLoadExpr(Expr expr) {
167+
TTranslatedValueExpr(Expr expr) {
168168
not ignoreExpr(expr) and
169169
not isNativeCondition(expr) and
170170
not isFlexibleCondition(expr)

cpp/ql/src/semmle/code/cpp/ir/internal/TranslatedExpr.qll

Lines changed: 105 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,41 @@ TranslatedExpr getTranslatedExpr(Expr expr) {
1717
}
1818

1919
/**
20-
* The IR translation of an expression that was either directly present in the
21-
* AST as an `Expr` (`TranslatedExpr`) or was synthesized from something other
22-
* than an `Expr` .
20+
* The IR translation of some part of an expression.
21+
* A single `Expr` may consist of multiple `TranslatedExpr` objects. Every
22+
* `Expr` has a single `TranslatedCoreExpr`, which produces the result of the
23+
* expression before any implicit lvalue-to-rvalue conversion. Any expression
24+
* with an lvalue-to-rvalue conversion will also have a `TranslatedLoad` to
25+
* perform that conversion on the original result. A few expressions have
26+
* additional `TranslatedExpr` objects that compute intermediate values, such
27+
* as the `TranslatedAllocatorCall` and `TranslatedAllocationSize` within the
28+
* translation of a `NewExpr`.
2329
*/
24-
abstract class TranslatedOrSynthesizedExpr extends TranslatedElement {
30+
abstract class TranslatedExpr extends TranslatedElement {
31+
Expr expr;
32+
2533
/**
2634
* Gets the instruction that produces the result of the expression.
2735
*/
2836
abstract Instruction getResult();
29-
}
3037

31-
/**
32-
* The IR translation of some part of an expression. This could be the
33-
* expression itself (`TranslatedExpr`), or some other construct synthesized
34-
* from an `Expr` (e.g. `TranslatedAllocatorCall`).
35-
*/
36-
abstract class TranslatedFromExpr extends TranslatedElement {
37-
Expr expr;
38+
/**
39+
* Holds if this `TranslatedExpr` produces the final result of the original
40+
* expression from the AST.
41+
*
42+
* For example, in `y = x;`, the TranslatedLoad for the VariableAccess `x`
43+
* produces the result of that VariableAccess expression, but the
44+
* TranslatedVariableAccess for `x` does not. The TranslatedVariableAccess
45+
* for `y` does produce its result, however, because there is no load on `y`.
46+
*/
47+
abstract predicate producesExprResult();
48+
49+
/**
50+
* Gets the type of the result produced by this expression.
51+
*/
52+
final Type getResultType() {
53+
result = expr.getType().getUnspecifiedType()
54+
}
3855

3956
override final Locatable getAST() {
4057
result = expr
@@ -44,6 +61,13 @@ abstract class TranslatedFromExpr extends TranslatedElement {
4461
result = expr.getEnclosingFunction()
4562
}
4663

64+
/**
65+
* Gets the expression from which this `TranslatedExpr` is generated.
66+
*/
67+
final Expr getExpr() {
68+
result = expr
69+
}
70+
4771
/**
4872
* Gets the `TranslatedFunction` containing this expression.
4973
*/
@@ -53,34 +77,17 @@ abstract class TranslatedFromExpr extends TranslatedElement {
5377
}
5478

5579
/**
56-
* The IR translation of an expression.
80+
* The IR translation of the "core" part of an expression. This is the part of
81+
* the expression that produces the result value of the expression, before any
82+
* lvalue-to-rvalue conversion on the result. Every expression has a single
83+
* `TranslatedCoreExpr`.
5784
*/
58-
abstract class TranslatedExpr extends TranslatedOrSynthesizedExpr,
59-
TranslatedFromExpr {
85+
abstract class TranslatedCoreExpr extends TranslatedExpr {
6086
override final string toString() {
6187
result = expr.toString()
6288
}
6389

64-
final Expr getExpr() {
65-
result = expr
66-
}
67-
68-
final Type getResultType() {
69-
result = expr.getType().getUnspecifiedType()
70-
}
71-
72-
/**
73-
* Holds if this `TranslatedExpr` produces the final result of the original
74-
* expression from the AST.
75-
*
76-
* For example, in `y = x;`, the TranslatedLoad for the VariableAccess `x`
77-
* produces the result of that VariableAccess expression, but the
78-
* TranslatedVariableAccess for `x` does not. The TranslatedVariableAccess
79-
* for `y` does produce its result, however, because there is no load on `y`.
80-
*/
81-
final predicate producesExprResult() {
82-
// A load always produces the result of the expression.
83-
this instanceof TranslatedLoad or
90+
override final predicate producesExprResult() {
8491
// If there's no load, then this is the only TranslatedExpr for this
8592
// expression.
8693
not expr.hasLValueToRValueConversion() or
@@ -110,7 +117,7 @@ abstract class TranslatedExpr extends TranslatedOrSynthesizedExpr,
110117
}
111118
}
112119

113-
class TranslatedConditionValue extends TranslatedExpr, ConditionContext,
120+
class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
114121
TTranslatedConditionValue {
115122
TranslatedConditionValue() {
116123
this = TTranslatedConditionValue(expr)
@@ -286,11 +293,19 @@ class TranslatedConditionValue extends TranslatedExpr, ConditionContext,
286293
}
287294
}
288295

296+
/**
297+
* IR translation of an implicit lvalue-to-rvalue conversion on the result of
298+
* an expression.
299+
*/
289300
class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
290301
TranslatedLoad() {
291302
this = TTranslatedLoad(expr)
292303
}
293304

305+
override string toString() {
306+
result = "Load of " + expr.toString()
307+
}
308+
294309
override Instruction getFirstInstruction() {
295310
result = getOperand().getFirstInstruction()
296311
}
@@ -303,8 +318,11 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
303318
Type resultType, boolean isGLValue) {
304319
tag = LoadTag() and
305320
opcode instanceof Opcode::Load and
306-
resultType = getResultType() and
307-
isGLValue = isResultGLValue()
321+
resultType = expr.getType().getUnspecifiedType() and
322+
if expr.isGLValueCategory() then
323+
isGLValue = true
324+
else
325+
isGLValue = false
308326
}
309327

310328
override Instruction getInstructionSuccessor(InstructionTag tag,
@@ -337,8 +355,13 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
337355
)
338356
}
339357

340-
private TranslatedExpr getOperand() {
341-
result.getExpr() = expr and not result instanceof TranslatedLoad
358+
override final predicate producesExprResult() {
359+
// A load always produces the result of the expression.
360+
any()
361+
}
362+
363+
private TranslatedCoreExpr getOperand() {
364+
result.getExpr() = expr
342365
}
343366
}
344367

@@ -930,21 +953,24 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
930953
}
931954
}
932955

933-
abstract class TranslatedNonLoadExpr extends TranslatedExpr,
934-
TTranslatedNonLoadExpr {
935-
TranslatedNonLoadExpr() {
936-
this = TTranslatedNonLoadExpr(expr)
937-
}
938-
}
939-
940-
abstract class TranslatedNonConstantExpr extends TranslatedNonLoadExpr {
956+
/**
957+
* IR translation of an expression whose value is not known at compile time.
958+
*/
959+
abstract class TranslatedNonConstantExpr extends TranslatedCoreExpr {
941960
TranslatedNonConstantExpr() {
961+
this = TTranslatedValueExpr(expr) and
942962
not expr.isConstant()
943963
}
944964
}
945965

946-
abstract class TranslatedConstantExpr extends TranslatedNonLoadExpr {
966+
/**
967+
* IR translation of an expression with a compile-time constant value. This
968+
* includes not only literals, but also "integral constant expressions" (e.g.
969+
* `1 + 2`).
970+
*/
971+
abstract class TranslatedConstantExpr extends TranslatedCoreExpr {
947972
TranslatedConstantExpr() {
973+
this = TTranslatedValueExpr(expr) and
948974
expr.isConstant()
949975
}
950976

@@ -1022,7 +1048,15 @@ class TranslatedStringLiteral extends TranslatedConstantExpr {
10221048
}
10231049
}
10241050

1025-
abstract class TranslatedValueExpr extends TranslatedNonConstantExpr {
1051+
/**
1052+
* IR translation of an expression that performs a single operation on its
1053+
* operands and returns the result.
1054+
*/
1055+
abstract class TranslatedSingleInstructionExpr extends
1056+
TranslatedNonConstantExpr {
1057+
/**
1058+
* Gets the `Opcode` of the operation to be performed.
1059+
*/
10261060
abstract Opcode getOpcode();
10271061

10281062
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
@@ -1038,7 +1072,7 @@ abstract class TranslatedValueExpr extends TranslatedNonConstantExpr {
10381072
}
10391073
}
10401074

1041-
class TranslatedUnaryExpr extends TranslatedValueExpr {
1075+
class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr {
10421076
TranslatedUnaryExpr() {
10431077
expr instanceof NotExpr or
10441078
expr instanceof ComplementExpr or
@@ -1323,7 +1357,10 @@ private Opcode comparisonOpcode(ComparisonOperation expr) {
13231357
expr instanceof GEExpr and result instanceof Opcode::CompareGE
13241358
}
13251359

1326-
class TranslatedBinaryOperation extends TranslatedValueExpr {
1360+
/**
1361+
* IR translation of a simple binary operation.
1362+
*/
1363+
class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr {
13271364
TranslatedBinaryOperation() {
13281365
expr instanceof BinaryArithmeticOperation or
13291366
expr instanceof BinaryBitwiseOperation or
@@ -1735,7 +1772,7 @@ class TranslatedAssignOperation extends TranslatedAssignment {
17351772
* call in the source code, or could be a call that is part of the translation
17361773
* of a higher-level constructor (e.g. the allocator call in a `NewExpr`).
17371774
*/
1738-
abstract class TranslatedCall extends TranslatedOrSynthesizedExpr {
1775+
abstract class TranslatedCall extends TranslatedExpr {
17391776
override final TranslatedElement getChild(int id) {
17401777
// We choose the child's id in the order of evaluation.
17411778
// The qualifier is evaluated before the call target, because the value of
@@ -1868,7 +1905,7 @@ abstract class TranslatedCall extends TranslatedOrSynthesizedExpr {
18681905
* Gets the argument with the specified `index`. Does not include the `this`
18691906
* argument.
18701907
*/
1871-
abstract TranslatedOrSynthesizedExpr getArgument(int index);
1908+
abstract TranslatedExpr getArgument(int index);
18721909

18731910
/**
18741911
* If there are any arguments, gets the first instruction of the first
@@ -1894,8 +1931,8 @@ abstract class TranslatedCall extends TranslatedOrSynthesizedExpr {
18941931
* We have to synthesize this because not all `NewExpr` nodes have an allocator
18951932
* call, and even the ones that do pass an `ErrorExpr` as the argument.
18961933
*/
1897-
abstract class TranslatedAllocationSize extends TranslatedOrSynthesizedExpr,
1898-
TranslatedFromExpr, TTranslatedAllocationSize {
1934+
abstract class TranslatedAllocationSize extends TranslatedExpr,
1935+
TTranslatedAllocationSize {
18991936
NewOrNewArrayExpr newExpr;
19001937

19011938
TranslatedAllocationSize() {
@@ -1907,6 +1944,10 @@ abstract class TranslatedAllocationSize extends TranslatedOrSynthesizedExpr,
19071944
result = "Allocation size for " + newExpr.toString()
19081945
}
19091946

1947+
override final predicate producesExprResult() {
1948+
none()
1949+
}
1950+
19101951
override final Instruction getResult() {
19111952
result = getInstruction(AllocationSizeTag())
19121953
}
@@ -2050,8 +2091,8 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
20502091
* The IR translation of a call to `operator new` as part of a `new` or `new[]`
20512092
* expression.
20522093
*/
2053-
class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedCall,
2054-
TranslatedFromExpr {
2094+
class TranslatedAllocatorCall extends TTranslatedAllocatorCall,
2095+
TranslatedCall {
20552096
NewOrNewArrayExpr newExpr;
20562097

20572098
TranslatedAllocatorCall() {
@@ -2063,6 +2104,10 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedCall,
20632104
result = "Allocator call for " + newExpr.toString()
20642105
}
20652106

2107+
override final predicate producesExprResult() {
2108+
none()
2109+
}
2110+
20662111
override final Instruction getFirstCallTargetInstruction() {
20672112
result = getInstruction(CallTargetTag())
20682113
}
@@ -2109,7 +2154,7 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedCall,
21092154
any()
21102155
}
21112156

2112-
override final TranslatedOrSynthesizedExpr getArgument(int index) {
2157+
override final TranslatedExpr getArgument(int index) {
21132158
// If the allocator is the default operator new(void*), there will be no
21142159
// allocator call in the AST. Otherwise, there will be an allocator call
21152160
// that includes all arguments to the allocator, including the size,
@@ -2152,7 +2197,7 @@ abstract class TranslatedCallExpr extends TranslatedNonConstantExpr,
21522197
result = getTranslatedExpr(call.getQualifier().getFullyConverted())
21532198
}
21542199

2155-
override final TranslatedOrSynthesizedExpr getArgument(int index) {
2200+
override final TranslatedExpr getArgument(int index) {
21562201
result = getTranslatedExpr(call.getArgument(index).getFullyConverted())
21572202
}
21582203
}

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22
#-----| params:
33
#-----| __va_list_tag::operator=() -> __va_list_tag &
44
#-----| params:
5+
#-----| operator new(unsigned long) -> void *
6+
#-----| params:
7+
#-----| 0: p#0
8+
#-----| Type = unsigned long
9+
#-----| operator delete(void *, unsigned long) -> void
10+
#-----| params:
11+
#-----| 0: p#0
12+
#-----| Type = void *
13+
#-----| 1: p#1
14+
#-----| Type = unsigned long
515
#-----| operator new(unsigned long, align_val_t) -> void *
616
#-----| params:
717
#-----| 0: p#0
@@ -24,16 +34,6 @@
2434
#-----| Type = unsigned long
2535
#-----| 1: p#1
2636
#-----| Type = align_val_t
27-
#-----| operator new(unsigned long) -> void *
28-
#-----| params:
29-
#-----| 0: p#0
30-
#-----| Type = unsigned long
31-
#-----| operator delete(void *, unsigned long) -> void
32-
#-----| params:
33-
#-----| 0: p#0
34-
#-----| Type = void *
35-
#-----| 1: p#1
36-
#-----| Type = unsigned long
3737
ir.cpp:
3838
# 1| Constants() -> void
3939
# 1| params:

0 commit comments

Comments
 (0)