Skip to content

Commit 1f01d80

Browse files
authored
Merge pull request github#8225 from jketema/ir-structured-bindings-translation
C++: Update the IR translation for structured bindings
2 parents 3719353 + 0c2cfa1 commit 1f01d80

File tree

9 files changed

+2834
-1422
lines changed

9 files changed

+2834
-1422
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Many queries now support structured bindings, as structured bindings are now handled in the IR translation.

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ newtype TInstructionTag =
7171
AsmTag() or
7272
AsmInputTag(int elementIndex) { exists(AsmStmt asm | exists(asm.getChild(elementIndex))) } or
7373
ThisAddressTag() or
74-
ThisLoadTag()
74+
ThisLoadTag() or
75+
StructuredBindingAccessTag()
7576

7677
class InstructionTag extends TInstructionTag {
7778
final string toString() { result = "Tag" }
@@ -221,4 +222,6 @@ string getInstructionTagId(TInstructionTag tag) {
221222
tag = ThisAddressTag() and result = "ThisAddress"
222223
or
223224
tag = ThisLoadTag() and result = "ThisLoad"
225+
or
226+
tag = StructuredBindingAccessTag() and result = "StructuredBindingAccess"
224227
}

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ private import semmle.code.cpp.ir.implementation.IRType
33
private import semmle.code.cpp.ir.implementation.Opcode
44
private import semmle.code.cpp.ir.implementation.internal.OperandTag
55
private import semmle.code.cpp.ir.internal.CppType
6+
private import semmle.code.cpp.ir.internal.IRUtilities
67
private import semmle.code.cpp.ir.internal.TempVariableTag
78
private import InstructionTag
89
private import TranslatedCondition
@@ -813,7 +814,9 @@ abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr {
813814
}
814815

815816
class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
816-
TranslatedNonFieldVariableAccess() { not expr instanceof FieldAccess }
817+
TranslatedNonFieldVariableAccess() {
818+
not expr instanceof FieldAccess and not isNonReferenceStructuredBinding(expr.getTarget())
819+
}
817820

818821
override Instruction getFirstInstruction() {
819822
if exists(this.getQualifier())
@@ -860,6 +863,71 @@ class TranslatedFieldAccess extends TranslatedVariableAccess {
860863
}
861864
}
862865

866+
/**
867+
* The IR translation of a variable access of a structured binding, where the type
868+
* of the structured binding is not of a reference type, e.g., `x0` and `x1`
869+
* in `auto [x0, x1] = xs` where `xs` is an array. Although the type of the
870+
* structured binding is a non-reference type, the structured binding behaves
871+
* like a reference. Hence, the translation requires a `VariableAddress` followed
872+
* by a `Load` instead of only a `VariableAddress` as produced by
873+
* `TranslatedVariableAccess`.
874+
*/
875+
class TranslatedStructuredBindingVariableAccess extends TranslatedNonConstantExpr {
876+
override VariableAccess expr;
877+
878+
TranslatedStructuredBindingVariableAccess() { isNonReferenceStructuredBinding(expr.getTarget()) }
879+
880+
override Instruction getFirstInstruction() {
881+
// Structured bindings cannot be qualified.
882+
result = this.getInstruction(StructuredBindingAccessTag())
883+
}
884+
885+
override TranslatedElement getChild(int id) {
886+
// Structured bindings cannot be qualified.
887+
none()
888+
}
889+
890+
override Instruction getResult() { result = this.getInstruction(LoadTag()) }
891+
892+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
893+
tag = StructuredBindingAccessTag() and
894+
kind instanceof GotoEdge and
895+
result = this.getInstruction(LoadTag())
896+
or
897+
tag = LoadTag() and
898+
kind instanceof GotoEdge and
899+
result = this.getParent().getChildSuccessor(this)
900+
}
901+
902+
override Instruction getChildSuccessor(TranslatedElement child) { none() }
903+
904+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
905+
tag = StructuredBindingAccessTag() and
906+
opcode instanceof Opcode::VariableAddress and
907+
resultType = getTypeForGLValue(this.getLValueReferenceType())
908+
or
909+
tag = LoadTag() and
910+
opcode instanceof Opcode::Load and
911+
resultType = getTypeForPRValue(this.getLValueReferenceType())
912+
}
913+
914+
private LValueReferenceType getLValueReferenceType() {
915+
// The extractor ensures `result` exists when `isNonReferenceStructuredBinding(expr.getTarget())` holds.
916+
result.getBaseType() = expr.getUnspecifiedType()
917+
}
918+
919+
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
920+
tag = LoadTag() and
921+
operandTag instanceof AddressOperandTag and
922+
result = this.getInstruction(StructuredBindingAccessTag())
923+
}
924+
925+
override IRVariable getInstructionVariable(InstructionTag tag) {
926+
tag = StructuredBindingAccessTag() and
927+
result = getIRUserVariable(expr.getEnclosingFunction(), expr.getTarget())
928+
}
929+
}
930+
863931
class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
864932
override FunctionAccess expr;
865933

cpp/ql/lib/semmle/code/cpp/ir/internal/IRUtilities.qll

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ private Type getDecayedType(Type type) {
1111
result.(PointerType).getBaseType() = type.(ArrayType).getBaseType()
1212
}
1313

14+
/**
15+
* Holds if the sepcified variable is a structured binding with a non-reference
16+
* type.
17+
*/
18+
predicate isNonReferenceStructuredBinding(Variable v) {
19+
v.isStructuredBinding() and
20+
not v.getUnspecifiedType() instanceof ReferenceType
21+
}
22+
1423
/**
1524
* Get the actual type of the specified variable, as opposed to the declared type.
1625
* This returns the type of the variable after any pointer decay is applied, and
@@ -30,7 +39,12 @@ Type getVariableType(Variable v) {
3039
result = v.getInitializer().getExpr().getType()
3140
or
3241
not exists(v.getInitializer()) and result = v.getType()
33-
else result = v.getType()
42+
else
43+
if isNonReferenceStructuredBinding(v)
44+
then
45+
// The extractor ensures `r` exists when `isNonReferenceStructuredBinding(v)` holds.
46+
exists(LValueReferenceType r | r.getBaseType() = v.getUnspecifiedType() | result = r)
47+
else result = v.getType()
3448
)
3549
}
3650

0 commit comments

Comments
 (0)