@@ -3,6 +3,7 @@ private import semmle.code.cpp.ir.implementation.IRType
33private import semmle.code.cpp.ir.implementation.Opcode
44private import semmle.code.cpp.ir.implementation.internal.OperandTag
55private import semmle.code.cpp.ir.internal.CppType
6+ private import semmle.code.cpp.ir.internal.IRUtilities
67private import semmle.code.cpp.ir.internal.TempVariableTag
78private import InstructionTag
89private import TranslatedCondition
@@ -813,7 +814,9 @@ abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr {
813814}
814815
815816class 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+
863931class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
864932 override FunctionAccess expr ;
865933
0 commit comments