Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6167a55

Browse files
author
Robert Marsh
authored
Merge pull request #1380 from dave-bartolomeo/dave/RangeFor
C++: IR support for range-based `for` loops
2 parents 0fa06e5 + aff85c5 commit 6167a55

8 files changed

Lines changed: 492 additions & 4 deletions

File tree

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import semmle.code.cpp.ir.implementation.raw.IR
33
private import semmle.code.cpp.ir.internal.OperandTag
44
private import semmle.code.cpp.ir.internal.TempVariableTag
55
private import InstructionTag
6+
private import TranslatedCondition
67
private import TranslatedElement
78
private import TranslatedExpr
89
private import TranslatedStmt
@@ -159,6 +160,23 @@ cached private module Cached {
159160
)
160161
)
161162
or
163+
// Range-based for loop:
164+
// Any edge from within the update of the loop to the condition of
165+
// the loop is a back edge.
166+
exists(TranslatedRangeBasedForStmt s, TranslatedCondition condition |
167+
s instanceof TranslatedRangeBasedForStmt and
168+
condition = s.getCondition() and
169+
result = condition.getFirstInstruction() and
170+
exists(TranslatedElement inUpdate, InstructionTag tag |
171+
result = inUpdate.getInstructionSuccessor(tag, kind) and
172+
exists(TranslatedElement update |
173+
update = s.getUpdate() |
174+
inUpdate = update.getAChild*()
175+
) and
176+
instruction = inUpdate.getInstruction(tag)
177+
)
178+
)
179+
or
162180
// Goto statement:
163181
// As a conservative approximation, any edge out of `goto` is a back edge
164182
// unless it goes strictly forward in the program text. A `goto` whose

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,44 @@ class TranslatedVariableDeclarationEntry extends TranslatedVariableDeclaration,
191191
}
192192
}
193193

194+
/**
195+
* Gets the `TranslatedRangeBasedForVariableDeclaration` that represents the declaration of
196+
* `var`.
197+
*/
198+
TranslatedRangeBasedForVariableDeclaration getTranslatedRangeBasedForVariableDeclaration(
199+
LocalVariable var) {
200+
result.getVariable() = var
201+
}
202+
203+
/**
204+
* Represents the IR translation of a compiler-generated variable in a range-based `for` loop.
205+
*/
206+
class TranslatedRangeBasedForVariableDeclaration extends TranslatedVariableDeclaration,
207+
TTranslatedRangeBasedForVariableDeclaration {
208+
RangeBasedForStmt forStmt;
209+
LocalVariable var;
210+
211+
TranslatedRangeBasedForVariableDeclaration() {
212+
this = TTranslatedRangeBasedForVariableDeclaration(forStmt, var)
213+
}
214+
215+
override string toString() {
216+
result = var.toString()
217+
}
218+
219+
override Locatable getAST() {
220+
result = var
221+
}
222+
223+
override Function getFunction() {
224+
result = forStmt.getEnclosingFunction()
225+
}
226+
227+
override LocalVariable getVariable() {
228+
result = var
229+
}
230+
}
231+
194232
TranslatedConditionDecl getTranslatedConditionDecl(ConditionDeclExpr expr) {
195233
result.getAST() = expr
196234
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,16 @@ newtype TTranslatedElement =
359359
declStmt.getADeclarationEntry() = entry
360360
)
361361
} or
362+
// A compiler-generated variable to implement a range-based for loop. These don't have a
363+
// `DeclarationEntry` in the database, so we have to go by the `Variable` itself.
364+
TTranslatedRangeBasedForVariableDeclaration(RangeBasedForStmt forStmt, LocalVariable var) {
365+
translateStmt(forStmt) and
366+
(
367+
var = forStmt.getRangeVariable() or
368+
var = forStmt.getBeginEndDeclaration().getADeclaration() or
369+
var = forStmt.getVariable()
370+
)
371+
} or
362372
// An allocator call in a `new` or `new[]` expression
363373
TTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) {
364374
not ignoreExpr(newExpr)

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,105 @@ class TranslatedForStmt extends TranslatedLoop {
630630
}
631631
}
632632

633+
/**
634+
* The IR translation of a range-based `for` loop.
635+
* Note that this class does not extend `TranslatedLoop`. This is because the "body" of the
636+
* range-based `for` loop consists of the per-iteration variable declaration followed by the
637+
* user-written body statement. It is easier to handle the control flow of the loop separately,
638+
* rather than synthesizing a single body or complicating the interface of `TranslatedLoop`.
639+
*/
640+
class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
641+
override RangeBasedForStmt stmt;
642+
643+
override TranslatedElement getChild(int id) {
644+
id = 0 and result = getRangeVariableDeclaration() or
645+
id = 1 and result = getBeginVariableDeclaration() or
646+
id = 2 and result = getEndVariableDeclaration() or
647+
id = 3 and result = getCondition() or
648+
id = 4 and result = getUpdate() or
649+
id = 5 and result = getVariableDeclaration() or
650+
id = 6 and result = getBody()
651+
}
652+
653+
override Instruction getFirstInstruction() {
654+
result = getRangeVariableDeclaration().getFirstInstruction()
655+
}
656+
657+
override Instruction getChildSuccessor(TranslatedElement child) {
658+
(
659+
child = getRangeVariableDeclaration() and
660+
result = getBeginVariableDeclaration().getFirstInstruction()
661+
) or
662+
(
663+
child = getBeginVariableDeclaration() and
664+
result = getEndVariableDeclaration().getFirstInstruction()
665+
) or
666+
(
667+
child = getEndVariableDeclaration() and
668+
result = getCondition().getFirstInstruction()
669+
) or
670+
(
671+
child = getVariableDeclaration() and
672+
result = getBody().getFirstInstruction()
673+
) or
674+
(
675+
child = getBody() and
676+
result = getUpdate().getFirstInstruction()
677+
) or
678+
(
679+
child = getUpdate() and
680+
result = getCondition().getFirstInstruction()
681+
)
682+
}
683+
684+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType,
685+
boolean isGLValue) {
686+
none()
687+
}
688+
689+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
690+
none()
691+
}
692+
693+
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
694+
child = getCondition() and result = getVariableDeclaration().getFirstInstruction()
695+
}
696+
697+
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
698+
child = getCondition() and result = getParent().getChildSuccessor(this)
699+
}
700+
701+
private TranslatedRangeBasedForVariableDeclaration getRangeVariableDeclaration() {
702+
result = getTranslatedRangeBasedForVariableDeclaration(stmt.getRangeVariable())
703+
}
704+
705+
private TranslatedRangeBasedForVariableDeclaration getBeginVariableDeclaration() {
706+
result = getTranslatedRangeBasedForVariableDeclaration(stmt.getBeginVariable())
707+
}
708+
709+
private TranslatedRangeBasedForVariableDeclaration getEndVariableDeclaration() {
710+
result = getTranslatedRangeBasedForVariableDeclaration(stmt.getEndVariable())
711+
}
712+
713+
// Public for getInstructionBackEdgeSuccessor
714+
final TranslatedCondition getCondition() {
715+
result = getTranslatedCondition(stmt.getCondition().getFullyConverted())
716+
}
717+
718+
// Public for getInstructionBackEdgeSuccessor
719+
final TranslatedExpr getUpdate() {
720+
result = getTranslatedExpr(stmt.getUpdate().getFullyConverted())
721+
}
722+
723+
private TranslatedRangeBasedForVariableDeclaration getVariableDeclaration() {
724+
result = getTranslatedRangeBasedForVariableDeclaration(stmt.getVariable())
725+
}
726+
727+
private TranslatedStmt getBody() {
728+
result = getTranslatedStmt(stmt.getStmt())
729+
}
730+
}
731+
633732
class TranslatedJumpStmt extends TranslatedStmt {
634733
override JumpStmt stmt;
635734

cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
675675
* ```
676676
* the result is `int x`.
677677
*/
678-
Variable getVariable() { result = getChild(4).(DeclStmt).getADeclaration() }
678+
LocalVariable getVariable() { result = getChild(4).(DeclStmt).getADeclaration() }
679679

680680
/**
681681
* Gets the expression giving the range to iterate over.
@@ -689,7 +689,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
689689
Expr getRange() { result = getRangeVariable().getInitializer().getExpr() }
690690

691691
/** Gets the compiler-generated `__range` variable after desugaring. */
692-
Variable getRangeVariable() {
692+
LocalVariable getRangeVariable() {
693693
result = getChild(0).(DeclStmt).getADeclaration()
694694
}
695695

@@ -709,6 +709,16 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
709709
*/
710710
DeclStmt getBeginEndDeclaration() { result = this.getChild(1) }
711711

712+
/** Gets the compiler-generated `__begin` variable after desugaring. */
713+
LocalVariable getBeginVariable() {
714+
result = getBeginEndDeclaration().getDeclaration(0)
715+
}
716+
717+
/** Gets the compiler-generated `__end` variable after desugaring. */
718+
LocalVariable getEndVariable() {
719+
result = getBeginEndDeclaration().getDeclaration(1)
720+
}
721+
712722
/**
713723
* Gets the compiler-generated `++__begin` which is the update
714724
* expression of this for statement after desugaring. It will
@@ -718,8 +728,8 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
718728
Expr getUpdate() { result = this.getChild(3) }
719729

720730
/** Gets the compiler-generated `__begin` variable after desugaring. */
721-
Variable getAnIterationVariable() {
722-
result = getUpdate().getAChild().(VariableAccess).getTarget()
731+
LocalVariable getAnIterationVariable() {
732+
result = getBeginVariable()
723733
}
724734
}
725735

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

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7427,3 +7427,146 @@ ir.cpp:
74277427
#-----| -1: this
74287428
#-----| Type = const lambda [] type at line 1045, col. 23 *
74297429
#-----| ValueCategory = prvalue(load)
7430+
# 1050| vector<int>& vector<int>::operator=(vector<int> const&)
7431+
# 1050| params:
7432+
#-----| 0: p#0
7433+
#-----| Type = const vector<int> &
7434+
# 1050| vector<int>& vector<int>::operator=(vector<int>&&)
7435+
# 1050| params:
7436+
#-----| 0: p#0
7437+
#-----| Type = vector<int> &&
7438+
# 1051| vector<int>::iterator& vector<int>::iterator::operator=(vector<int>::iterator const public&)
7439+
# 1051| params:
7440+
#-----| 0: p#0
7441+
#-----| Type = const iterator &
7442+
# 1051| vector<int>::iterator& vector<int>::iterator::operator=(vector<int>::iterator&&)
7443+
# 1051| params:
7444+
#-----| 0: p#0
7445+
#-----| Type = iterator &&
7446+
# 1053| vector<T>::iterator& vector<T>::iterator::operator++()
7447+
# 1053| params:
7448+
# 1053| vector<int>::iterator& vector<int>::iterator::operator++()
7449+
# 1053| params:
7450+
# 1054| T& vector<T>::iterator::operator*() const
7451+
# 1054| params:
7452+
# 1054| int& vector<int>::iterator::operator*() const
7453+
# 1054| params:
7454+
# 1056| bool vector<T>::iterator::operator!=(vector<T>::iterator) const
7455+
# 1056| params:
7456+
# 1056| 0: right
7457+
# 1056| Type = iterator
7458+
# 1056| bool vector<int>::iterator::operator!=(vector<int>::iterator) const
7459+
# 1056| params:
7460+
# 1056| 0: right
7461+
# 1056| Type = iterator
7462+
# 1059| vector<T>::iterator vector<T>::begin() const
7463+
# 1059| params:
7464+
# 1059| vector<int>::iterator vector<int>::begin() const
7465+
# 1059| params:
7466+
# 1060| vector<T>::iterator vector<T>::end() const
7467+
# 1060| params:
7468+
# 1060| vector<int>::iterator vector<int>::end() const
7469+
# 1060| params:
7470+
# 1064| bool operator==<T>(iterator, iterator)
7471+
# 1064| params:
7472+
# 1064| 0: left
7473+
# 1064| Type = iterator
7474+
# 1064| 1: right
7475+
# 1064| Type = iterator
7476+
# 1066| bool operator!=<T>(iterator, iterator)
7477+
# 1066| params:
7478+
# 1066| 0: left
7479+
# 1066| Type = iterator
7480+
# 1066| 1: right
7481+
# 1066| Type = iterator
7482+
# 1068| void RangeBasedFor(vector<int> const&)
7483+
# 1068| params:
7484+
# 1068| 0: v
7485+
# 1068| Type = const vector<int> &
7486+
# 1068| body: { ... }
7487+
# 1069| 0: for(...:...) ...
7488+
# 1069| 0: declaration
7489+
# 1069| 1: declaration
7490+
# 1069| 2: call to operator!=
7491+
# 1069| Type = bool
7492+
# 1069| ValueCategory = prvalue
7493+
#-----| -1: (const iterator)...
7494+
#-----| Conversion = glvalue conversion
7495+
#-----| Type = const iterator
7496+
#-----| ValueCategory = lvalue
7497+
#-----| expr: (__begin)
7498+
#-----| Type = iterator
7499+
#-----| ValueCategory = lvalue
7500+
#-----| 0: (__end)
7501+
#-----| Type = iterator
7502+
#-----| ValueCategory = prvalue(load)
7503+
# 1069| 3: (reference dereference)
7504+
# 1069| Type = iterator
7505+
# 1069| ValueCategory = lvalue
7506+
# 1069| expr: call to operator++
7507+
# 1069| Type = iterator &
7508+
# 1069| ValueCategory = prvalue
7509+
#-----| -1: (__begin)
7510+
#-----| Type = iterator
7511+
#-----| ValueCategory = lvalue
7512+
# 1069| 4: declaration
7513+
# 1069| 5: { ... }
7514+
# 1070| 0: if (...) ...
7515+
# 1070| 0: ... > ...
7516+
# 1070| Type = bool
7517+
# 1070| ValueCategory = prvalue
7518+
# 1070| 0: e
7519+
# 1070| Type = int
7520+
# 1070| ValueCategory = prvalue(load)
7521+
# 1070| 1: 0
7522+
# 1070| Type = int
7523+
# 1070| Value = 0
7524+
# 1070| ValueCategory = prvalue
7525+
# 1070| 1: { ... }
7526+
# 1071| 0: continue;
7527+
# 1069| 1: label ...:
7528+
# 1075| 1: for(...:...) ...
7529+
# 1075| 0: declaration
7530+
# 1075| 1: declaration
7531+
# 1075| 2: call to operator!=
7532+
# 1075| Type = bool
7533+
# 1075| ValueCategory = prvalue
7534+
#-----| -1: (const iterator)...
7535+
#-----| Conversion = glvalue conversion
7536+
#-----| Type = const iterator
7537+
#-----| ValueCategory = lvalue
7538+
#-----| expr: (__begin)
7539+
#-----| Type = iterator
7540+
#-----| ValueCategory = lvalue
7541+
#-----| 0: (__end)
7542+
#-----| Type = iterator
7543+
#-----| ValueCategory = prvalue(load)
7544+
# 1075| 3: (reference dereference)
7545+
# 1075| Type = iterator
7546+
# 1075| ValueCategory = lvalue
7547+
# 1075| expr: call to operator++
7548+
# 1075| Type = iterator &
7549+
# 1075| ValueCategory = prvalue
7550+
#-----| -1: (__begin)
7551+
#-----| Type = iterator
7552+
#-----| ValueCategory = lvalue
7553+
# 1075| 4: declaration
7554+
# 1075| 5: { ... }
7555+
# 1076| 0: if (...) ...
7556+
# 1076| 0: ... < ...
7557+
# 1076| Type = bool
7558+
# 1076| ValueCategory = prvalue
7559+
# 1076| 0: (reference dereference)
7560+
# 1076| Type = int
7561+
# 1076| ValueCategory = prvalue(load)
7562+
# 1076| expr: e
7563+
# 1076| Type = const int &
7564+
# 1076| ValueCategory = prvalue(load)
7565+
# 1076| 1: 5
7566+
# 1076| Type = int
7567+
# 1076| Value = 5
7568+
# 1076| ValueCategory = prvalue
7569+
# 1076| 1: { ... }
7570+
# 1077| 0: break;
7571+
# 1079| 2: label ...:
7572+
# 1080| 3: return ...

0 commit comments

Comments
 (0)